From mcnepp02 at googlemail.com Mon Mar 1 06:19:10 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Mon, 1 Mar 2010 14:19:10 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> Message-ID: <1f5b87141003010619w6caec0f7j230881d864f3c219@mail.gmail.com> I may be missing something here, but I don't understand why the discussion about type-safety of closures deals only with arrays of closures. Isn't the root cause for the type-safety-problem the lack of a comprehensive runtime-type-info that preserves the entire signature of the closure? Isn't this exactly the same problem that we're having with erased generic types already today? This code yields an 'unchecked' warning in current Java: Object obj = new ArrayList(); List list = (ArrayList)obj; I do not see how that differs from a similar situation with closures: Object obj = #void() { System.out.println("hello world"); }; #void() closure = (#void())obj; This should also trigger an 'unchecked' warning, right? From forax at univ-mlv.fr Mon Mar 1 07:15:30 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 01 Mar 2010 16:15:30 +0100 Subject: Accessing non-final local variables from a lambda expression In-Reply-To: <4B8ADD25.10900@oracle.com> References: <15e8b9d21002252336o2f7280d2v157a9acd38ab29da@mail.gmail.com> <201002261701.24155.peter.levart@marand.si> <560fb5ed1002271405j63a3db17s8809eecc2ce1ae2c@mail.gmail.com> <201002282044.09069.peter.levart@marand.si> <4B8ADD25.10900@oracle.com> Message-ID: <4B8BDA12.2050609@univ-mlv.fr> Le 28/02/2010 22:16, Fredrik ?hrstr?m a ?crit : > Peter Levart wrote: > >> With "frame object" I meant an object, allocated on the heap whose class is constructed by >> compiler and holds all captured local variables (whether final or non-final). I don't know why but >> this terminology is used by Neal and others. >> >> With MethodHandles, local vars can be captured one-by-one via (MethodHandles.insertArgument) but >> it might still be better to construct a single "frame object" to hold all of them when their >> number reaches a certain limit or when at least one of them is non-final. >> >> > Be aware that insertArgument might very well be implemented as > a "closure" using a frame object. See the sample implementation in: > http://tinyurl.com/q8v92o#InsertArgument > and the appendArgument implementation at the end of > http://tinyurl.com/pekyrc > > //Fredrik > Peter, latest java.dyn API has a method named MethodHandles.insertArguments (with a 's' at the end) that allow to insert more than one argument. R?mi From neal at gafter.com Mon Mar 1 07:51:03 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 1 Mar 2010 07:51:03 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003010619w6caec0f7j230881d864f3c219@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <1f5b87141003010619w6caec0f7j230881d864f3c219@mail.gmail.com> Message-ID: <15e8b9d21003010751r4cf26cbcx6765a6c505526467@mail.gmail.com> On Mon, Mar 1, 2010 at 6:19 AM, Gernot Neppert wrote: > I may be missing something here, but I don't understand why the > discussion about type-safety of closures deals only with arrays of > closures. Because that is the only aspect of the problem that has implications for the syntax proposal that started this thread. > Isn't the root cause for the type-safety-problem the lack of a > comprehensive runtime-type-info that preserves the entire signature of > the closure? > Isn't this exactly the same problem that we're having with erased > generic types already today? Yes, exactly. And we can't solve the problem with function types without solving the problem with generics. Solving the problem with generics is outside the scope of this project, would require an order of magnitude more manpower than is devoted to this project, would require extending the SE 7 schedule by an additional year or two (or more), and would probably break backward compatibility. None of that is going to happen. > I do not see how that differs from a similar situation with closures: > > Object obj = #void() { System.out.println("hello world"); }; > #void() closure = (#void())obj; > > This should also trigger an 'unchecked' warning, right? Yes. That is the implication of section 4.7 of lambda's draft specification. Cheers, Neal From Alex.Buckley at Sun.COM Mon Mar 1 10:13:13 2010 From: Alex.Buckley at Sun.COM (Alex Buckley) Date: Mon, 01 Mar 2010 10:13:13 -0800 Subject: A reminder of Project Lambda's scope In-Reply-To: <201002271046.49540.david.goodenough@linkchoose.co.uk> References: <4B886052.5070305@sun.com> <201002271046.49540.david.goodenough@linkchoose.co.uk> Message-ID: <4B8C03B9.1010804@sun.com> David Goodenough wrote: > Does this mean that obvious extensions of things, like field references being > a logical extension of method references, can also be considered? What you consider to be an obvious extension is not necessarily an obvious extension. The strawman and mailing list are already very wide in scope, so no, field references may not be discussed here. I encourage you to start an OpenJDK project about method and field references. See http://openjdk.java.net/projects/. The Compiler Group is the obvious project sponsor. Alex From Alex.Buckley at Sun.COM Mon Mar 1 14:13:33 2010 From: Alex.Buckley at Sun.COM (Alex Buckley) Date: Mon, 01 Mar 2010 14:13:33 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> Message-ID: <4B8C3C0D.2020309@sun.com> 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 Neal Gafter wrote: > *A Syntax Option for Project Lambda (Closures for > Java) > * > > It was noted recently on the Project Lambda mailing > listthat > 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 . 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, > the code would look something like this: > > *static** * > > *##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 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. > From forax at univ-mlv.fr Mon Mar 1 14:38:13 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 01 Mar 2010 23:38:13 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B8C3C0D.2020309@sun.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> Message-ID: <4B8C41D5.1080607@univ-mlv.fr> 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) >> * >> >> It was noted recently on the Project Lambda mailing >> listthat >> 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. 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, >> the code would look something like this: >> >> *static*** >> >> *##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 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. >> >> > From Alex.Buckley at Sun.COM Mon Mar 1 14:43:57 2010 From: Alex.Buckley at Sun.COM (Alex Buckley) Date: Mon, 01 Mar 2010 14:43:57 -0800 Subject: Implementing recursive lambda with MethodHandle In-Reply-To: <15e8b9d21002231558m857e18bg7df0ea746a0cc366@mail.gmail.com> References: <4B826FEF.4070605@univ-mlv.fr> <17b2302a1002221219v1678540dw2a669f8dd2ebe734@mail.gmail.com> <15e8b9d21002221310x1f054fc2y4292022172d9abd6@mail.gmail.com> <9FF0EECF0E58D849A9D537E324DDDC0D0452EFA7@NZURC102PEX1.ubsw.net> <6C819E7F-7249-4689-B1D7-EDB910201738@gmail.com> <17b2302a1002231119k2c7ded43obaf34f2ae8940692@mail.gmail.com> <15e8b9d21002231123t47bc8904h3784aaa83de429d@mail.gmail.com> <15e8b9d21002231558m857e18bg7df0ea746a0cc366@mail.gmail.com> Message-ID: <4B8C432D.5040906@sun.com> Neal Gafter wrote: > I think it is fine for values of function type to inherit these > methods from Object, and for getClass() to return MethodHandle.class > or the class of some compiler-generated implementation object. Right. Though I would say that because function types are not class types, inheritance is not the right mechanism. It is necessary to specify that a function type implicitly declares methods like Object's public methods, akin to what interface types do. Alex From neal at gafter.com Mon Mar 1 15:42:26 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 1 Mar 2010 15:42:26 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B8C3C0D.2020309@sun.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> Message-ID: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> On Mon, Mar 1, 2010 at 2:13 PM, Alex Buckley wrote: > 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. That wasn't the reason for the restriction. The reason was that reification would be a breaking change, and therefore will not happen. So there's no need to plan for it. By comparison to the infix notation the other forms look clumsy. It doesn't make sense to cripple the function type syntax to support something that is and always will be unsafe. In any case, my proposed syntax doesn't prevent you from handling arrays of function type, it just requires (like every problem in computer science) a bit of indirection. For example, one could hold arrays using this public class ArrayHolder { public final final T[] array; public ArrayHolder(T[] array) { this.array = array; } } Now, one can store the array from inside a varargs method: void method(()->int ... numberGenerators) { ArrayHolder<()->int> gens = new ArrayHolder<>(numberGenerators); } And from there pass them around all you want. This is unsafe, so the syntactic gyrations don't bother me. > 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 I agree with R?mi that you don't need so many parens. You could put the throws either before or after the result type. I'd also suggest keeping the lambda and function type syntax forms parallel in part because the lambda is the primary, and currently only, way to get a value of function type. For example either (String -> int throws SomeException) variable = (String x -> 3); or, as R?mi suggests (String throws SomeException -> int) variable = (String x -> 3); So the curry example would be something like static (T->(U throws X->V)) curry((T,U throws X->V) function) { return (T t->(U u->function.(t,u))); } Cheers, Neal From jjb at google.com Mon Mar 1 15:55:24 2010 From: jjb at google.com (Joshua Bloch) Date: Mon, 1 Mar 2010 15:55:24 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> Message-ID: <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> Neal, On Mon, Mar 1, 2010 at 3:42 PM, Neal Gafter wrote: > By comparison to the infix notation the other forms look clumsy. > This issue is controversial. There are those who find the "infix" (arrow) notation particularly ugly in the context of Java. > It doesn't make sense to > cripple the function type syntax to support something that is and > always will be unsafe. > This language ("cripple the function type syntax") seems far too strong. I think what you're saying is more like "I like the arrow notation better." Safe or not, I think it's highly desirable that we be able to express the type that represents an array of function types. Otherwise function types will be second-class citizens: you can (to the best of my knowledge) express arrays of every other Java type. This is not the sort of invariant to give up lightly. Josh From markmahieu at googlemail.com Mon Mar 1 16:05:32 2010 From: markmahieu at googlemail.com (Mark Mahieu) Date: Tue, 2 Mar 2010 00:05:32 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> Message-ID: <6DAD8A9A-24E2-4C35-A5D1-E15B9B7457AD@googlemail.com> On 1 Mar 2010, at 23:42, Neal Gafter wrote: > > I agree with R?mi that you don't need so many parens. You could put > the throws either before or after the result type. I'd also suggest > keeping the lambda and function type syntax forms parallel in part > because the lambda is the primary, and currently only, way to get a > value of function type. For example either > > (String -> int throws SomeException) variable = (String x -> 3); > > or, as R?mi suggests > > (String throws SomeException -> int) variable = (String x -> 3); > > So the curry example would be something like > > static > (T->(U throws X->V)) curry((T,U throws X->V) function) { > return (T t->(U u->function.(t,u))); > } > > Cheers, > Neal > That's pretty good in my eyes - for these non-trivial types I think it's much easier to follow than the equivalent code using the currently proposed syntax. It's easy to see where each function type or lambda begins and ends (and editors/IDEs will be able to offer matching bracket highlighting as they do elsewhere in the language). Mark From neal at gafter.com Mon Mar 1 16:14:22 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 1 Mar 2010 16:14:22 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> Message-ID: <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> On Mon, Mar 1, 2010 at 3:55 PM, Joshua Bloch wrote: >> ?It doesn't make sense to >> cripple the function type syntax to support something that is and >> always will be unsafe. > > This language ("cripple ?the function type syntax") seems far too strong. On the contrary, (to paraphrase Futurama) it isn't far too strong enough! > Safe or not, I think it's highly desirable that we be able to express the > type that represents an array of function types. ?Otherwise function types > will be second-class citizens: you can (to the best of my knowledge) express > arrays of every other Java type. This is not the sort of invariant to give > up lightly. If we add exception transparency, I expect we will do so by adding disjunction types, and you will not be able to express arrays of those either (never mind intersection types). From jjb at google.com Mon Mar 1 16:58:54 2010 From: jjb at google.com (Joshua Bloch) Date: Mon, 1 Mar 2010 16:58:54 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> Message-ID: <17b2302a1003011658x44f4b567n6513864b19b5e46@mail.gmail.com> Neal, On Mon, Mar 1, 2010 at 4:14 PM, Neal Gafter wrote: > > > > Safe or not, I think it's highly desirable that we be able to express the > > type that represents an array of function types. Otherwise function > types > > will be second-class citizens: you can (to the best of my knowledge) > express > > arrays of every other Java type. This is not the sort of invariant to > give > > up lightly. > > If we add exception transparency, I expect we will do so by adding > disjunction types, and you will not be able to express arrays of those > either (never mind intersection types). > Why do you say we won't be able to express arrays of disjunction types? Is there some fundamental reason it's not possible? If so, then yes, they'd be second-class citizens (if we decided to support them). But that's no reason to turn function types into second class citizens when we have a choice in the matter. Josh From neal at gafter.com Mon Mar 1 17:55:02 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 1 Mar 2010 17:55:02 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003011658x44f4b567n6513864b19b5e46@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> <17b2302a1003011658x44f4b567n6513864b19b5e46@mail.gmail.com> Message-ID: <15e8b9d21003011755o196c1a59k4abe34c490705abe@mail.gmail.com> On Mon, Mar 1, 2010 at 4:58 PM, Joshua Bloch wrote: > Why do you say we won't be able to express arrays of disjunction types? Is > there some fundamental reason it's not possible? No, we can technically add support for anything we want, but if the syntax can't be used safely in the language, it doesn't make much sense. We'd really have to go out of our way to make up a syntax that is more awkward just to make sure we can express something that we cannot implement. What you're proposing is a false orthogonality. I understand what 308 did by adding support for annotating types in only some (but not all) places in the language for no particular technical reasons but absence of compelling use cases, but in this case we have sound technical reasons as well. (If it wasn't clear, disjunction types are not reifiable). > If so, then yes, they'd be > second-class citizens (if we decided to support them). But that's no reason > to turn function types into second class citizens when we have a choice in > the matter. Whether the syntax makes it obvious or not, function types would be second-class citizens in precisely the way you're complaining about: there's no correct way to make arrays of them. We'd not be doing any favors by pretending otherwise in the syntax. From jjb at google.com Mon Mar 1 18:01:40 2010 From: jjb at google.com (Joshua Bloch) Date: Mon, 1 Mar 2010 18:01:40 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011755o196c1a59k4abe34c490705abe@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> <17b2302a1003011658x44f4b567n6513864b19b5e46@mail.gmail.com> <15e8b9d21003011755o196c1a59k4abe34c490705abe@mail.gmail.com> Message-ID: <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> Neal, I don't find this argument convincing. As I understand it, you're saying that function types and disjunction types will have the same level of runtime support as generics. So they should have the same level of expressiveness as well: it should be possible to describe, but not create (except implicitly for varargs) arrays of these types. Josh On Mon, Mar 1, 2010 at 5:55 PM, Neal Gafter wrote: > On Mon, Mar 1, 2010 at 4:58 PM, Joshua Bloch wrote: > > Why do you say we won't be able to express arrays of disjunction types? > Is > > there some fundamental reason it's not possible? > > No, we can technically add support for anything we want, but if the > syntax can't be used safely in the language, it doesn't make much > sense. We'd really have to go out of our way to make up a syntax that > is more awkward just to make sure we can express something that we > cannot implement. What you're proposing is a false orthogonality. I > understand what 308 did by adding support for annotating types in only > some (but not all) places in the language for no particular technical > reasons but absence of compelling use cases, but in this case we have > sound technical reasons as well. (If it wasn't clear, disjunction > types are not reifiable). > > > If so, then yes, they'd be > > second-class citizens (if we decided to support them). But that's no > reason > > to turn function types into second class citizens when we have a choice > in > > the matter. > > Whether the syntax makes it obvious or not, function types would be > second-class citizens in precisely the way you're complaining about: > there's no correct way to make arrays of them. We'd not be doing any > favors by pretending otherwise in the syntax. > From reinier at zwitserloot.com Mon Mar 1 18:18:30 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 2 Mar 2010 03:18:30 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> Message-ID: <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> In regards to: (String x -> 3) What is this going to look like when the body of the closure is not a single expression but a block? --Reinier Zwitserloot On Tue, Mar 2, 2010 at 12:42 AM, Neal Gafter wrote: > On Mon, Mar 1, 2010 at 2:13 PM, Alex Buckley wrote: > > 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. > > That wasn't the reason for the restriction. The reason was that > reification would be a breaking change, and therefore will not happen. > So there's no need to plan for it. By comparison to the infix > notation the other forms look clumsy. It doesn't make sense to > cripple the function type syntax to support something that is and > always will be unsafe. > > In any case, my proposed syntax doesn't prevent you from handling > arrays of function type, it just requires (like every problem in > computer science) a bit of indirection. For example, one could hold > arrays using this > > public class ArrayHolder { > public final final T[] array; > public ArrayHolder(T[] array) { > this.array = array; > } > } > > Now, one can store the array from inside a varargs method: > > void method(()->int ... numberGenerators) { > ArrayHolder<()->int> gens = new ArrayHolder<>(numberGenerators); > } > > And from there pass them around all you want. This is unsafe, so the > syntactic gyrations don't bother me. > > > 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 > > I agree with R?mi that you don't need so many parens. You could put > the throws either before or after the result type. I'd also suggest > keeping the lambda and function type syntax forms parallel in part > because the lambda is the primary, and currently only, way to get a > value of function type. For example either > > (String -> int throws SomeException) variable = (String x -> 3); > > or, as R?mi suggests > > (String throws SomeException -> int) variable = (String x -> 3); > > So the curry example would be something like > > static > (T->(U throws X->V)) curry((T,U throws X->V) function) { > return (T t->(U u->function.(t,u))); > } > > Cheers, > Neal > > From neal at gafter.com Mon Mar 1 18:32:38 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 1 Mar 2010 18:32:38 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <17b2302a1003011555p307bbd65gfd1276c0f578f251@mail.gmail.com> <15e8b9d21003011614x54eb6ccfs11fe3a614bf2ee7f@mail.gmail.com> <17b2302a1003011658x44f4b567n6513864b19b5e46@mail.gmail.com> <15e8b9d21003011755o196c1a59k4abe34c490705abe@mail.gmail.com> <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> Message-ID: <15e8b9d21003011832j2b6e72aekd4025895bab4fb32@mail.gmail.com> On Mon, Mar 1, 2010 at 6:01 PM, Joshua Bloch wrote: > I don't find this argument convincing. As I understand it, you're saying > that function types and disjunction types will have the same level of > runtime support as generics. So they should have the same level of > expressiveness as well: it should be possible to describe, but not create > (except implicitly for varargs) arrays of these types. I don't find this argument convincing. You're saying that because something else that is useless appears in the language, we should provide more useless things by analogy. From peter.levart at marand.si Mon Mar 1 23:49:54 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 08:49:54 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> Message-ID: <201003020849.54620.peter.levart@marand.si> I think we don't need statement lambdas if we allow expression to be preceeded by statements (like in block expression of CfJ0.6b): Lambda: '(' FormalParameters_opt '->' Statements_opt Expression ')' for void lambdas "void" keyword could be defined as expression of type void: (->void) lambda = (-> System.out.println("Hello!"); void); Regarding arrays of function types, this syntax: FunctionType: '(' ParameterTypes_opt Throws_opt '->' ReturnType ')' is perfectly combinable with array type syntax. Peter On Tuesday 02 March 2010 03:18:30 Reinier Zwitserloot wrote: > In regards to: > > (String x -> 3) > > What is this going to look like when the body of the closure is not a single > expression but a block? > > --Reinier Zwitserloot > From peter.levart at marand.si Tue Mar 2 00:10:04 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 09:10:04 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <6DAD8A9A-24E2-4C35-A5D1-E15B9B7457AD@googlemail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <6DAD8A9A-24E2-4C35-A5D1-E15B9B7457AD@googlemail.com> Message-ID: <201003020910.04583.peter.levart@marand.si> On Tuesday 02 March 2010 01:05:32 Mark Mahieu wrote: > > On 1 Mar 2010, at 23:42, Neal Gafter wrote: > > > > I agree with R?mi that you don't need so many parens. You could put > > the throws either before or after the result type. I'd also suggest > > keeping the lambda and function type syntax forms parallel in part > > because the lambda is the primary, and currently only, way to get a > > value of function type. For example either > > > > (String -> int throws SomeException) variable = (String x -> 3); > > > > or, as R?mi suggests > > > > (String throws SomeException -> int) variable = (String x -> 3); > > > > So the curry example would be something like > > > > static > > (T->(U throws X->V)) curry((T,U throws X->V) function) { > > return (T t->(U u->function.(t,u))); > > } > > > > Cheers, > > Neal > > > > That's pretty good in my eyes - for these non-trivial types I think it's much easier to follow than the equivalent code using the currently proposed syntax. > > It's easy to see where each function type or lambda begins and ends (and editors/IDEs will be able to offer matching bracket highlighting as they do elsewhere in the language). > > Mark > I also think that it is good that this syntax doesn't abuse '#' for yet another thing. There's already non-java identifiers and method references that use it. Adding function types and lambdas to the mix increases confusion as everything looks similar. Peter From schulz at the-loom.de Tue Mar 2 00:31:15 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Tue, 02 Mar 2010 09:31:15 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> Message-ID: <4B8CCCD3.1090305@the-loom.de> Neal wrote: > (String -> int throws SomeException) variable = (String x -> 3); Regarding function types, this is just what I proposed some mails ago ;) Regarding lambdas, I disagree. There is no need to make both look alike, in fact, I prefer lambdas to resemble (anonymous) methods. R?mi's suggestion > (String throws SomeException -> int) variable = (String x -> 3); unfortunately places the arrow in between the definitions of the possible outcome of an invocation. Cheers, Stefan From peter.levart at marand.si Tue Mar 2 00:38:41 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 09:38:41 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003020849.54620.peter.levart@marand.si> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> <201003020849.54620.peter.levart@marand.si> Message-ID: <201003020938.41458.peter.levart@marand.si> On Tuesday 02 March 2010 08:49:54 Peter Levart wrote: > for void lambdas "void" keyword could be defined as expression of type void: > > (->void) lambda = (-> System.out.println("Hello!"); void); > Oops, this would make an ambiguous syntax: (->void) lambda = (->void); Or is this still unambiguous since type and expression appear in different contexts? Peter From peter.levart at marand.si Tue Mar 2 02:16:40 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 11:16:40 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <15e8b9d21003011755o196c1a59k4abe34c490705abe@mail.gmail.com> <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> Message-ID: <201003021116.40451.peter.levart@marand.si> On Tuesday 02 March 2010 03:01:40 Joshua Bloch wrote: > Neal, > > I don't find this argument convincing. As I understand it, you're saying > that function types and disjunction types will have the same level of > runtime support as generics. So they should have the same level of > expressiveness as well: it should be possible to describe, but not create > (except implicitly for varargs) arrays of these types. > > Josh > The same level of expressiveness could be achived if we had a denotable form of common function supertype: FT (which could be different in syntax from function types in general). In analogy with the following: new List[10] // illegal new List[10] // legal The function types variant: new (int -> int)[10] // illegal new FT[10] // legal I wouldn't equate FT with MethodHandle since that would be an implementation detail. I wouldn't equate it with a marker interface either. The specification could just define it as a way to create arrays of raw function type. But is this any better than new Object[] ? Regards, Peter From peter.levart at marand.si Tue Mar 2 02:27:08 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 11:27:08 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003021116.40451.peter.levart@marand.si> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <17b2302a1003011801u5444b8d3u2a19a67435dfbc6@mail.gmail.com> <201003021116.40451.peter.levart@marand.si> Message-ID: <201003021127.08477.peter.levart@marand.si> On Tuesday 02 March 2010 11:16:40 Peter Levart wrote: > On Tuesday 02 March 2010 03:01:40 Joshua Bloch wrote: > > Neal, > > > > I don't find this argument convincing. As I understand it, you're saying > > that function types and disjunction types will have the same level of > > runtime support as generics. So they should have the same level of > > expressiveness as well: it should be possible to describe, but not create > > (except implicitly for varargs) arrays of these types. > > > > Josh > > > > The same level of expressiveness could be achived if we had a denotable form of common function supertype: FT (which could be different in syntax from function types in general). > > In analogy with the following: > > new List[10] // illegal > new List[10] // legal > > The function types variant: > > new (int -> int)[10] // illegal > new FT[10] // legal > > > I wouldn't equate FT with MethodHandle since that would be an implementation detail. I wouldn't equate it with a marker interface either. The specification could just define it as a way to create arrays of raw function type. But is this any better than new Object[] ? > > Regards, Peter > > No, I'm wrong this time. You were asking for the same level of expresivenes in specifying arrays of function type not creating instances of them. Peter From peter.levart at marand.si Tue Mar 2 03:41:02 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 12:41:02 +0100 Subject: A syntax option (function types versus arrays) Message-ID: <201003021241.02792.peter.levart@marand.si> On Tuesday 02 March 2010 08:58:28 Joshua Bloch wrote: > Peter, > > On Mon, Mar 1, 2010 at 11:49 PM, Peter Levart wrote: > > > I think we don't need statement lambdas if we allow expression to be > > preceeded by statements (like in block expression of CfJ0.6b): > > > > Lambda: > > '(' FormalParameters_opt '->' Statements_opt Expression ')' > > > > for void lambdas "void" keyword could be defined as expression of type > > void: > > > > (->void) lambda = (-> System.out.println("Hello!"); void); > > > > Why do you like this better than the current proposal? > > Josh > Regarding function types syntax I don't really have a preference to the order of (parameter types, return type, throws types) but I think that a syntax that composes well (nests) is better. In this regard the current proposal is not the best of all alternatives. I also think that visual similarity between the syntax-es of function types and lambda expressions is desired although not necessary. Recently I had a suggestion that is actually similar to the Neal's preferred syntax but with the order of return type reversed: FunctionType: ReturnType '#' '(' ParameterTypeList_opt Throws_opt ')' This can be viewed as: FunctionType: ReturnType '<-' '(' ParameterTypeList_opt Throws_opt ')' It nests better and at least Arabs would find it natural ;-) Regarding preference to expression lambdas, I think they provide a way to avoid defining the meaning of "return" at present time. The 1st release of lambdas in JDK7 could simply disallow "return". Experience gathered from the milions of Java developers in comming years would help shape a decision of what to do with "return" (be it local or transparent) for the next release in JDK8 which could add statement lambdas as well. I think that gradual additions to the language where 1st addition leaves open options for the future is a safe path. We may argue till the end what is going to work better but why not just wait and see what is going to be missed the most? Regards, Peter From peter.levart at marand.si Tue Mar 2 04:00:07 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 13:00:07 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <4B8C3C0D.2020309@sun.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> Message-ID: <201003021300.07818.peter.levart@marand.si> On Tuesday 02 March 2010 00:42:26 Neal Gafter wrote: > > 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 > > I agree with R?mi that you don't need so many parens. You could put > the throws either before or after the result type. I'd also suggest > keeping the lambda and function type syntax forms parallel in part > because the lambda is the primary, and currently only, way to get a > value of function type. For example either > > (String -> int throws SomeException) variable = (String x -> 3); > > or, as R?mi suggests > > (String throws SomeException -> int) variable = (String x -> 3); > > So the curry example would be something like > > static > (T->(U throws X->V)) curry((T,U throws X->V) function) { > return (T t->(U u->function.(t,u))); > } > > Cheers, > Neal What about casts? Double parens? Is it possible, fom syntax perspective, that for function types the cast would simply state a function type without additional parens? CastExpression: ( ReferenceTypeNoFunctionType ) UnaryExpressionNotPlusMinus FunctionType UnaryExpressionNotPlusMinus Regards, Peter From peter.levart at marand.si Tue Mar 2 04:29:08 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 2 Mar 2010 13:29:08 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003021241.02792.peter.levart@marand.si> References: <201003021241.02792.peter.levart@marand.si> Message-ID: <201003021329.08709.peter.levart@marand.si> On Tuesday 02 March 2010 12:41:02 Peter Levart wrote: > Regarding preference to expression lambdas, I think they provide a way to avoid defining the meaning of "return" at present time. The 1st release of lambdas in JDK7 could simply disallow "return". Experience gathered from the milions of Java developers in comming years would help shape a decision of what to do with "return" (be it local or transparent) for the next release in JDK8 which could add statement lambdas as well. > > I think that gradual additions to the language where 1st addition leaves open options for the future is a safe path. We may argue till the end what is going to work better but why not just wait and see what is going to be missed the most? For example: What would have been if JDK1.5 disallowed arrays of parameterized types? Would have they been added to the language in JDK6? Would there be a strong demand to add them? Maybe just in varargs methods. Regards, Peter From scolebourne at joda.org Tue Mar 2 05:44:11 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 2 Mar 2010 13:44:11 +0000 Subject: External reference: FCM v0.5 Message-ID: <4b4f45e01003020544g70c7b3ecpaf666ff77becd08c@mail.gmail.com> Following Neal's lead, here is the text of the FCM proposal v0.5 as formal submission for Lambda. http://docs.google.com/View?id=ddhp95vd_6hg3qhc The semantic and syntax choices sections at the end I believe continue to be pertinent for this discussion, as they document /why/ we chose what we chose. The following were changed in the unpublished v0.6 of FCM - Removed named inner methods - Only allow conversion to single method interfaces, not single abstract method classes - Clarify types of method, constructor and field literals - Propose generic parameters for Method and Field - Clarify conversion of references when syntax is ambiguous - Add arrow rule for conversion - Note transparency limitations when interacting with single method interfaces If there is interest, I'll tart up and publish FCM v0.6. Stephen -------------------------------------- First-class methods: Java-style closures Version 0.5 Stephen Colebourne, UK Stefan Schulz, Germany I. Problem In Java, the method is the principal construct where application logic resides. At present, a method can only exist within a class and cannot be manipulated or referenced in any simple manner. Other languages permit a block of application logic to be referenced outside of a class, and this is often referred to as a function or a closure. A Java developer can approach the power of functions/closures using two techniques - reflection [5] and inner classes [1:15.9]. However, neither is very developer friendly - reflection is not compile-time safe or refactorable, and inner classes are very verbose. As a result of the difficulty of writing code using reflection and inner classes the techniques tend to be limited to callbacks between an application and a framework. However, the majority of uses of functions or closures in other languages is for small-scale code re-use. This typically involves refactoring out common sections of code which may have a common beginning and end, but different code in the middle. In this scenario, the extracted code isn't run at a much later time like a callback is, but immediately as the original code would have done. To enable this power in Java, we propose to change the language to support the referencing and definition of methods as first-class objects. This provides much of the power of functions/closures but in a style familiar to Java developers. We further propose to enable the referencing of other class members - constructors and fields - as first-class citizens. This is a natural extension to First-class Methods. Sorting example The Comparator interface is the standard mechanism in Java to provide the code needed to sort lists. Here is a Comparator that sorts by length of String: List list = ... Collections.sort(list, new Comparator() { public int compare(String str1, String str2) { return str1.length() - str2.length(); } }); With the changes in this proposal, the code could be written as follows: List list = ... Collections.sort(list, #(String str1, String str2) { return str1.length() - str2.length(); }); This syntax is termed an anonymous inner method, and is a logical extension to the anonymous inner class concept. The conversion to a Comparator is automatic. Event listener example The Swing GUI framework makes widespread use of listeners to inform the application of events. These are frequently implemented as inner classes which delegate their behaviour to a 'normal' method on the class initialising the listener: public void init() { JButton button = ...; button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { handleAction(ev); } }); } public void handleAction(ActionEvent ev) { // handle event } With the changes in this proposal, the code could be written as follows: public void init() { JButton button = ...; button.addActionListener(this#handleAction(ActionEvent)); } public void handleAction(ActionEvent ev) { // handle event } This syntax uses a bound method reference to refer to a pre-existing method on a specific object. The conversion to an ActionListener is automatic. II. Member literals Member literals represent a literal form, similar to double quoted Strings, for referring to a class's members. There are three kinds of literals each referring to the respective type of member: method literals (1), constructor literals (2), and field literals (3). MemberLiteral: MethodLiteral ConstructorLiteral FieldLiteral All kinds of member literals follow the standard rules for visibility. A member literal may refer to a public member from anywhere, to a protected member only from subclasses and within the same package, to a default scope member from within the same package, and to a private member only from within that class. 1. Method literals A method literal refers to a method definition. The syntax consists of the class name, followed by the # (hash) symbol and the method name with parameter types. Rationale: The use of the # symbol is deliberate. The symbol is already used within Javadoc to separate the class name from the method name in exactly this manner. The method literal syntax merely brings the Javadoc convention into Java source code. We go on to use the same # symbol throughout the proposal for method related syntaxes, helping to provide consistency. Examples The following examples refer to static methods: Math#min(int, int) Collections#sort(List, Comparator) The following examples refer to instance methods: Integer#intValue() Object#equals(Object) Detail Method literals are, by definition, assignable to java.lang.reflect.Method. As such, it is possible to call any part of the API of Method directly: Class returnType = Integer#intValue().getReturnType(); This calls the getReturnType method on the Method object contextually created by the method literal. Syntax MethodLiteral: ClassType # Identifier ( TypeListopt ) 2. Constructor literals A constructor literal refers to a constructor definition. The syntax consists of the class name, followed by the # (hash) symbol and the constructor's parameter types. Examples ArrayList#(int) JButton#(String, Icon) Detail Constructor literals are by definition assignable to java.lang.reflect.Constructor, where T must be assignable from the referred class. It is a compile-time error to reference an abstract class' constructor. Syntax ConstructorLiteral: ClassType # ( TypeListopt ) 3. Field literals A field literal refers to a field definition. The syntax consists of the class name, followed by the # (hash) symbol and the field's name. Examples The following examples refer to static fields: Member#DECLARED Node#ELEMENT_NODE The following examples refer to instance fields: MyBean#name TaskEntry#priority Detail Field literals are by definition assignable to java.lang.reflect.Field. Syntax FieldLiteral: ClassType # Identifier III. Method types Method types are a way to define the signature of a method or block of code. As such, they must define the parameters, return type, and thrown exceptions. The syntax consists of the # (hash) symbol followed by parentheses. Within the parentheses the method signature is specified following the logical order of defining a method - the return type, followed by the parameter types in parentheses, followed by any exceptions. Rationale: The use of the # symbol provides a clear visual indication to the developer as to the start of the method type. We feel that using # is considerably clearer in use than the alternatives we examined, including using braces (curly brackets) and a Haskell like notation [2]. The order and style of the method type is very deliberately following that of a method declaration in Java. This is to allow developers to pickup the new syntax easily. Examples The following examples show various forms of method types, with various return types, parameters, and thrown exceptions: #(int(String, String)) #(void(String)) #(String(File) throws IOException) #(long()) The following example shows how a method type can be assigned to an ActionListener interface: #(void(ActionEvent)) method = ... ActionListener lnr = method; This will compile to code equivalent to: static class Outer$MethodType$1 implements ActionListener { private final #(void(ActionEvent)) target; public Outer$MethodType$1(#(void(ActionEvent)) target) { this.target = target; } public void actionPerformed(ActionEvent arg1) { target.invoke(arg1); } }; #(void(ActionEvent)) method = ... ActionListener im = new Outer$MethodType$1(method); Detail An instance of a method type supports a single method, invoke, that can be used to call the method. Both the arguments and the return type of the invoke method are fully type-safe. For example: #(boolean(String,String)) nullSafeEqualsMethod = ... boolean equal = nullSafeEqualsMethod.invoke("Hello", "Hi"); Method types will be implemented as a compiler-generated interface. Considerable investigation and study of the implementation of this concept has already been undertaken as part of the BGGA proposal [4] (function types). As such, we don't attempt to duplicate that work here. A method type may be assigned to a class or interface provided that the compiler-generated class has a single abstract method with a fully compatible signature. It is a compile error if there is zero or more than one abstract method. Syntax Type: MethodType MethodType: # ( ResultType ( TypeListopt ) Throwsopt ) IV. Method references Method references are a way to refer to a specific method and its environment such that it can be invoked. There are four kinds of method references: static method reference (A1), instance method references (A2), bound method references (A3) and constructor references (A4). They share a common auto-conversion mechanism for assigning a method reference to a class or interface (B). MethodReference: StaticMethodReference InstanceMethodReference BoundMethodReference ConstructorReference A1. Static method references A static method reference provides a type-safe way to obtain an object that can be used to invoke a static method. The syntax consists of the class name, followed by the # (hash) symbol and the static method name with parameter types. Examples The following example shows the method type to which a static method reference can be assigned: #(int(int, int)) ref = Math#min(int, int); This will compile to code equivalent to: static class Outer$StaticMethodReference$1 implements #(int(int, int)) { public int invoke(int arg1, int arg2) { return Math.min(arg1, arg2); } }; #(int(int, int)) ref = new Outer$StaticMethodReference$1(); Detail A static method reference has the same syntax form as a method literal. It becomes a method reference when it is assigned to, or passed to, a method type. At compilation time, the static method reference will be implemented by a compiler-generated class. The class will implement the method type that the reference is assigned to. Syntax StaticMethodReference: ClassType # Identifier ( TypeListopt ) A2. Instance method references An instance method reference provides a type-safe way to obtain an object that can be used to invoke an instance method. An instance method must be invoked on an object, so the reference is adjusted to pass the object as the first parameter. The syntax consists of the class name, followed by the # (hash) symbol and the instance method name with parameter types. Examples The following example shows the method type to which an instance method reference can be assigned. Note how the method type takes an additional parameter which is the object that will be invoked: #(int(List, Object)) ref = List#indexOf(Object); This will compile to code equivalent to: static class Outer$InstanceMethodReference$1 implements #(int(List, Object)) { public int invoke(List arg1, Object arg2) { return arg1.indexOf(arg2); } }; #(int(List, Object)) ref = new Outer$InstanceMethodReference$1(); Detail An instance method reference provides a bridge between object-oriented programming and procedural programming. It is the equivalent of turning an instance method into a static method, by passing the instance to be invoked as the first argument. An instance method reference has the same syntax form as a method literal. It becomes a method reference when it is assigned to, or passed to, a method type. At compilation time, the instance method reference will be implemented by a compiler-generated class. The class will implement the method type that the reference is assigned to. Syntax InstanceMethodReference: ClassType # Identifier ( TypeListopt ) A3. Bound method references A bound method reference provides a type-safe way to obtain an object that can be used to invoke an instance method. To achieve this, it captures the object that it is to be invoked on. The syntax consists of an expression yielding an object, followed by the # (hash) symbol and the method name with parameter types. Examples The following example shows the method type to which a static method reference can be assigned: List list = ... #(int(Object)) ref = list#indexOf(Object); This will compile to code equivalent to: static class Outer$BoundMethodReference$1 implements #(int(Object)) { private final List target; public Outer$BoundMethodReference$1(List target) { this.target = target; } public int invoke(Object arg1) { return target.indexOf(arg1); } }; List list = ... #(int(Object)) ref = new Outer$BoundMethodReference$1(target); Detail A bound method reference is more complex than a static or instance method reference because it captures the object that it is invoked on. This capturing provides a very quick and easy way to pass a callback to a framework. At compilation time, the bound method reference will be implemented by a compiler-generated class which stores the target object as an instance variable. The class will implement the method type that the reference is assigned to. Syntax BoundMethodReference: Primary # Identifier ( TypeListopt ) A4. Constructor references A constructor reference provides a type-safe way to obtain an object that can be used to invoke a constructor. The syntax consists of the class name, followed by the # (hash) symbol and the parameter types. Examples The following example shows the method type to which a constructor reference can be assigned: #(Integer(int)) ref = Integer#(int); This will compile to code equivalent to: static class Outer$ConstructorReference$1 implements #(Integer(int)) { public Integer invoke(int arg1) { return new Integer(arg1); } }; #(Integer(int)) ref = new Outer$ConstructorReference$1(); Detail A constructor reference has the same syntax form as a constructor literal. It becomes a constructor reference when it is assigned to, or passed to, a method type. At compilation time, the constructor reference will be implemented by a compiler-generated class. The class will implement the method type that the reference is assigned to. Syntax ConstructorReference: ClassType # ( TypeListopt ) B. Common rules and mechanisms Conversion to class or interface A method reference of any of the four kinds may be assigned to a class or interface providing that the compiler-generated class has a single abstract method with a fully compatible signature. It is a compile error if there is zero or more than one abstract method. The following example on a bound method reference creates a compiler-generated class implementing ActionListener where the single abstract method actionPerformed calls the handleAction method on this. ActionListener lnr = this#handleAction(ActionEvent ev); This assignment will be compiled to code equivalent to: static class Outer$InstanceReference$1 implements ActionListener { private final Outer target; public Outer$BoundMethodReference$1(Outer target) { this.target = target; } public void actionPerformed(ActionEvent arg1) { return target.handleAction(arg1); } }; ActionListener lnr = new Outer$InstanceReference$1(this); If the method handleAction is not accessible for any reason, a synthetic method will be generated by the compiler. The example on a constructor reference below creates a compiler-generated class implementing ViewFactory where the single abstract method create invokes the constructor on IconView. ViewFactory vf = IconView#(Element); This assignment will be compiled to code equivalent to: static class Outer$ConstructorReference$1 implements ViewFactory { public View create(Element arg1) { return new IconView(arg1); } }; ViewFactory vf = new Outer$ConstructorReference$1(); V. Inner methods Inner methods are a way of writing a method in-line within the body of another method. This is analogous to an inner class but for methods. There are two kinds of inner method: anonymous (A1) and named (A2). Both of which share some common rules and mechanisms (B). InnerMethod: AnonymousInnerMethod NamedInnerMethod A1. Anonymous inner methods An anonymous inner method is a method written within the body of another method. It has no name and may be assigned to a method type or a class/interface with a single abstract method. Examples The following example creates an anonymous inner method assigned to a method type: #(void(ActionEvent)) action = #(ActionEvent ev) { System.out.println("ActionEvent fired"); } This will compile to code equivalent to: static class Outer$InnerMethod$1 implements #(void(ActionEvent)) { public void invoke(ActionEvent arg1) { System.out.println("ActionEvent fired"); } }; #(void(ActionEvent)) im = new Outer$InnerMethod$1(); The following related example creates an anonymous inner method assigned to a single abstract method interface: ActionListener action = #(ActionEvent ev) { System.out.println("ActionEvent fired"); } This will compile to code equivalent to: static class Outer$InnerMethod$1 implements ActionListener { public void actionPerformed(ActionEvent arg1) { System.out.println("ActionEvent fired"); } }; ActionListener im = new Outer$InnerMethod$1(); Detail An anonymous inner method may be assigned to a matching method type or a single abstract method type. At compilation time, the anonymous inner method will be implemented as a method on a compiler-generated class. The class generated depends on the context to which the inner method is assigned: * If the context is a method type, then the compiler-generated class implements the method type and provides a type-safe invoke method containing the code from the inner method. * If the context is a class or interface with a single abstract method, then the compiler-generated class extends or implements the type and provides an implementation for the abstract method containing the code from the inner method. It is a compiler error to declare an anonymous inner method without a context type. It is also a compile error, if there is zero or more than one abstract method on the context class/interface. Syntax AnonymousInnerMethod: # InnerMethodParametersopt Block InnerMethodParameters: ( FormalParameterListopt ) A2. Named inner methods A named inner method is a method written within the body of another method that has a name associated with it. Examples The following example creates a named inner method assigned to a ThreadLocal with the aim of initialising the object correctly: private final AtomicInteger nextId = new AtomicInteger(0); private final ThreadLocal threadId = #initialValue() { return nextId.getAndIncrement(); }; This will compile to code equivalent to: static class Outer$InnerMethod$1 extends ThreadLocal { public Integer initialValue() { return nextId.getAndIncrement(); } }; ThreadLocal threadId = new Outer$InnerMethod$1(); Detail A named inner method may be assigned to a matching method type or the majority of other types. The name is used to determine which method will be overridden. At compilation time, the named inner method will be implemented as a method on a compiler-generated class. The class generated depends on the context to which the inner method is assigned. * If the context is a method type, then the compiler-generated class implements the method type and provides a type-safe invoke method containing the code from the inner method. In this case, the name is ignored. * If the context is a class or interface, then the compiler-generated class extends or implements the type and provides an implementation with a method containing the code from the inner method. The name and signature of the inner method must match a method from the context type such that the method is overridden. The resulting class must be concrete. Rationale: Previous versions of FCM proposed implementing abstract methods that were not overridden with empty stubs. After consideration, it was decided that this is too risky, and has been removed. As a result, the 'method compound' concept from v0.4 has also been removed. Thus you cannot implement MouseListener using FCM - for that you need an inner class. It is a compiler error to declare a named inner method without a context type. Syntax NamedInnerMethod: # Identifier InnerMethodParametersopt Block B. Common rules and mechanisms The content of inner methods has the following rules: * The return keyword returns from the method * The continue and break keywords are limited to the scope of the method * The this keyword refers to the nearest enclosing class in the source code * Private methods on the nearest enclosing class in the source code may be accessed * There is no ability for the inner method to access member methods or variables on the class that actually implements it * Local variables from the enclosing scope may be accessed, both read and write These rules are similar to those of inner class methods with two exceptions, the this keyword and local variables. Rationale: These rules are at the heart of what differentiates one closure proposal from another. The CICE proposal [3] provides a means to simplify the creation of inner classes. The complex semantics of this remain. The BGGA proposal [4] takes the opposite route and tries to remove all restrictions on the content of the block. This results in a different set of issues, such as using exceptions for control flow and the RestrictedFunction interface which considerably changes the allowed content of the block. The use of the keyword return to return a value from the inner method is driven by a desire to stay close to the existing Java syntax for methods. The BGGA proposal [4] uses the concept of last-line-no semicolon to return a value from a closure. We consider that error-prone, inflexible (as it doesn't allow early return) and unlike any other part of Java syntax. See the semantic choices section for more detail. Accessing this The this keyword applies to the nearest enclosing class within the source code. (i.e., it does not apply to the compiler-generated class that is created to hold the method when implemented.) The reason for this is simple - as far as the developer is concerned there is no visible class in the source code for this to refer to. In the following (contrived) example, the log method is called using this. The object that will be passed to the log method is the instance of MyClass that surrounds the inner method. public class MyClass { public void process() { #(void(String)) example = #(String message) { Logger.log(this, message); }; example.invoke("Logged message"); } } Accessing local variables Local variables in the enclosing scope will be fully accessible to the inner method. If the local variable has been declared final, then it will be read-only. Otherwise, it will be read-write. The conversion to allow local variables to be accessed from two places will occur at compile-time. The method that receives an inner method may run concurrently with the method that created the inner method. This might cause a race condition with any shared local variables. We propose an annotation, @ConcurrentLocalVariableAccess, that applies to the method parameter which receives the inner method. This can be used to act as a warning to the compiler and development environments to help avoid race conditions. Rationale: These rules for accessing local variables are the least restrictive possible. Any local variable may be accessed by any inner method. To avoid our previous concerns with race conditions we propose an annotation, used to provide warnings and development environment support. See the semantic choices section for more detail. Syntax when no parameters For an inner method not having parameters the parentheses may be omitted: #{ ... } #methodName{ ... } Rationale: The no argument case is fairly common, and the syntax looks considerably more appealing with the parentheses removed. Transparency When an inner method is invoked immediately (synchronously) by the higher order method that it is passed to, it can be useful to handle exceptions more fully. What is required, is that any checked exception that could be thrown by a statement in the inner method block is transparently made to be an exception of the higher order method. The BGGA proposal [4] provides mechanisms to achieve this, and we reference that work here. VI. Further examples The following sections present some application scenarios for the proposed language enhancements. Executor The executor part of the concurrency framework allows a task to be submitted to run in another thread. This is typically written as an inner class at present: Executor exec = ...; exec.execute(new Runnable() { public void run() { // code to run in another thread } }); With the changes in this proposal, the code could be written as an anonymous inner method as follows: Executor exec = ...; exec.execute(#{ // code to run in another thread }); ThreadLocal initialization The ThreadLocal class provides a protected method to allow easy initialization. This is intended to be used as an inner class at present: private static final AtomicInteger nextId = new AtomicInteger(0); private static final ThreadLocal threadId = new ThreadLocal() { @Override protected Integer initialValue() { return nextId.getAndIncrement(); } }; With the changes in this proposal, the code could be written as a named inner method as follows: private static final AtomicInteger nextId = new AtomicInteger(0); private static final ThreadLocal threadId = #initialValue() { return nextId.getAndIncrement(); }; Inner loop example Java's collection framework provides the mechanism of iterators to loop on a collection's entries outside the collection. A common code pattern to find a matching entry looks like follows: PersonCache personCache = ... Person found = null; for (Person person : personCache.getPersonList()) { if (person.getAge() >= 18) { found = person; break; } } With the changes in this proposal, a method could be provided directly by the domain model, e.g., PersonCache allowing the code to be written as follows: PersonCache personCache = ... Person found = personCache.find(#(Person person) { return person.getAge() >= 18; }); This syntax uses an anonymous inner method to return a boolean true or false value. The inner method is called for each Person until the match is found and the inner method returns true. VII. Open issues 1. Is a widening conversion reasonable, either in general or on SAM types, e.g. for eliding unused parameters 2. API to handle method types 3. Is there a shortcut syntax to avoid specifying the types in a method literal or invocable method reference when the method is not overloaded, for example Object#equals(...) 4. Field references (any discussion on property references are out of scope for this document) 5. Is there a way to add support for currying and recursiveness from inner methods Semantic choices This section is Rationale about our semantic choices. In discussing this proposal we identified three basic use-cases - asynchronous (callbacks, like swing event listeners), synchronous (inline code refactoring, like sorting) and control abstraction (keyword based, like withLock or usingFile). The way in which each 'closure' proposal handles these cases is key to understanding their differences. With FCM we have, after much consideration, decided that the asynchronous and synchronous use cases do not truly differ in semantics. The control abstraction use case differs significantly however. With both the asynchronous and synchronous use case, an application developer can create an instance via an inner method and assign it to a local variable. The normal case is that the local variable is then passed to a method as a parameter (either an asynchronous or synchronous use case method). The local variable holding the inner method then falls out of scope at the end of the method it is defined in: public Person findPerson(PersonCache cache) { #(boolean(Person)) matcher = #(Person person) {...}; return cache.find(matcher); } In the example above, the matcher is being used synchronously - the matcher is created and used inline within a single method. However, it is possible to refactor the code slightly: public Person findPerson(PersonCache cache) { #(boolean(Person)) matcher = createMatcher(); return cache.find(matcher); } public #(boolean(Person)) createMatcher() { return #(Person person) {...}; } Now, the matcher is being created in one method, and used in another. Is this still a synchronous use case? Or an asynchronous one? Somewhere in between? The reality is that both use cases end up operating in the same way. Both are an inner method that can be assigned to a variable and passed around as per any other variable. This implies that using continue or break keywords within the inner method to refer to the method defining the inner method is meaningless. This is because the method defining the inner method and any loop may have been completed before the inner method is invoked. The same logic holds for using the return keyword to return from the enclosing method. As a result, FCM does not permit continue or break from within the inner method, and uses return to return a value from the inner method. We did have a concern that the asynchronous use case might get into a race condition over local variables, so in FCM v0.4 we restricted local variable access to read-only. However, the synchronous use case requires full read-write access to local variables. As a result FCM v0.5 allows full read-write access to local variables, and provides an annotation to warn if there may be concurrent access to local variables, which is where the real danger of race conditions lies. The final point of consideration was the control abstraction syntax. We established that the control abstraction use case is very different from the other use cases. public void process() { Lock lock = ... withLock(lock) { // code protected by the lock } } This example is at face value similar to the synchronous use case - the block of code is executed immediately and inline. However, there is a key difference - the block of code cannot be assigned to a variable within the process method. As a result, there is no way to pass the block of code to another method in the application - the block is fixed at this point in the code. A result of being fixed at this point in the code is that the semantics of the block are entirely different to blocks which can be assigned to a variable. The continue and break keywords should refer to the nearest loop, while the return keyword should refer to the enclosing method. In other words, it has the full semantics of a normal Java block. Implementing a mechanism to handle control abstraction is thus outside the scope of FCM. Syntax choices This section is Rationale about our syntax choices. When writing a proposal like FCM, there are two aspects to consider - syntax and semantics. Semantics is by far the most important, as it describes what happens in each scenario, and is the guts of the proposed change. However, it is almost always necessary to show examples, and for that you need to use a syntax. With FCM, we chose to use the # symbol as our key syntactic element. There were a number of reasons. Firstly, # is unused in Java at present. This means that there are no conflicts within the parser, simplifying the proposal. It also means that someone reading the resulting code doesn't have to think about what the symbol means (unlike ?, <, > or : for example). The # has been used by Java developers before however, as it is used in Javadoc. It has been pointed out that in most, if not all, cases, the parser could work out the meaning of the code without the use of the symbol at all. This is true, but a key feature of Java is readability. We believe that in this case, the extra symbol adds to the readability by clearly identifying the method syntax. This is important for inner methods which are likely to be running in another thread, hence the # acts as a kind of warning. Our decision on the method type syntax took quite a bit of thought. We chose a syntax which followed the layout of a Java method declaration - return type, then arguments in brackets, then any exceptions. We did consider a number of alternatives. For example, this is one alternate method type syntax that has some appeal (using the examples from the method types section): #(String, String return int) #(String) #(File return String throws IOException) #(return long) The last goal for our syntax was to be unambiguous. We didn't want to introduce any new elements of name shadowing. Finally, it should be borne in mind that the syntax is relatively unimportant - the semantics of the proposal are what really matter. Acknowledgments This proposal is based on the great work of the BGGA and CICE closure proposals. Our thanks go to Ricky Clarkson for acting as technical reviewer. In addition, the authors wish to thank all who contribute to the lively Java blog and forum community. Notes * References in this document are denoted by square brackets stating the reference number, optionally followed by a colon introducing a detail section. * The notation used for describing the syntax of new language elements corresponds to the one used in [1]. * Language elements not further described in this proposal are defined in [1]. Changes from v0.4 * Removed automatic creation of stubs when multiple abstract methods * Removed method compounds as a result of removing automatic creation of stubs * Changed local variable access to full read-write in all scenarios * Introduced a warning annotation to indicate possible concurrent access * Added section on transparency * Added semantic choices section References 1. The Java Language Specification, Third Edition http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html 2. The Haskell 98 Reports, Expressions, Section: 3.3 Curried Applications and Lambda Abstractions http://haskell.org/onlinereport/exps.html#sect3.3 3. B. Lee, D. Lea, J. Bloch: "Concise Instance Creation Expressions: Closures without Complexity" http://docs.google.com/Doc.aspx?id=k73_1ggr36h 4. G. Bracha, N. Gafter, J. Gosling, P. von der Ah?: "Closures for the Java Programming Language (v0.5)" http://www.javac.info 5. Java? Platform Standard Ed. 6, Reflection API http://java.sun.com/javase/6/docs/api/index.html?java/lang/reflect/package-summary.html 6. R. D. Tennent: "Principles of Programming Languages" Prentice Hall International, Englewood Cliffs, NJ, USA, 1981 From scolebourne at joda.org Tue Mar 2 06:08:57 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Tue, 2 Mar 2010 14:08:57 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B8C3C0D.2020309@sun.com> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <21208A19-213F-47CC-A062-4CF038651FA4@googlemail.com> <15e8b9d21002262008u6f947137v57069bd875c57242@mail.gmail.com> <4B8C3C0D.2020309@sun.com> Message-ID: <4b4f45e01003020608k6ef2c9dey47b752694f1f5711@mail.gmail.com> Firstly, as recorded elsewhere (lightweight interfaces), I believe that avoiding function types altogether may be the best option. However, if function types are a requirement, then I have to comment on Neal's proposed syntax option: (int,int)->int add = (int x, int y)->x+y; Personally, I dislike the -> arrow notation. I find the two symbols messy, and I believe they compose poorly wrt generics <>. The > character also works poorly wrt HTML, which affects usability in web forums and online examples (quite a significant problem with generics). Overall, the syntax above is markedly *different* to current Java syntax. That isn't a comment for or against. Different is a Good Thing if the new language feature is markedly different to what has gone before. Thus if Project Lambda wants function types and lambdas to be something new with markedly different rules (not usable with arrays, change to the meaning of return from inner class meaning), then the syntax should (must) look different. However, Different is a Bad Thing is the new language feature is a relatively simple derivation of an existing feature. FCM/CICE closures were, in many ways, a relatively simple derivation of inner classes, thus they looked and worked in a similar manner. Thus, I can't explicitly comment on Neal's syntax, because I'm unclear as to what *exactly* this project is changing the language for. (A focus on functional programming would encourage Neal's syntax, a focus on parallel would require something with importing of local variables, while a general simplification of inner classes tends towards FCM/CICE). Here is the Lambda v0.1.5 syntax (IIRC): #int(String, String) #void(String) #String(File) throws IOException #long() the FCM proposal: #(int(String, String)) #(void(String)) #(String(File) throws IOException) #(long()) the FCM alternate: #(String, String return int) #(String) #(File return String throws IOException) #(return long) I could accept any of these (including the return type last syntax so long as it is bracketed as above). But, visually, I really dislike "->": (String, String) -> int (String) -> void (File throws IOException) -> String () -> long Stephen On 1 March 2010 22:13, Alex Buckley wrote: > 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 > > Neal Gafter wrote: >> *A Syntax Option for Project Lambda (Closures for >> Java) >> * >> >> It was noted recently on the Project Lambda mailing >> listthat >> 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 . 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, >> the code would look something like this: >> >> *static** * >> >> *##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 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. >> > > From neal at gafter.com Tue Mar 2 07:43:39 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 2 Mar 2010 07:43:39 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003020938.41458.peter.levart@marand.si> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> <201003020849.54620.peter.levart@marand.si> <201003020938.41458.peter.levart@marand.si> Message-ID: <15e8b9d21003020743l296aec00n6180195bd56cdd4f@mail.gmail.com> On Tue, Mar 2, 2010 at 12:38 AM, Peter Levart wrote: > Oops, this would make an ambiguous syntax: > > ? ? ? ?(->void) lambda = (->void); > > Or is this still unambiguous since type and expression appear in different contexts? Yes, exactly. There are some interesting cases for the parser. o A simple identifier X is ambiguous between a function type and a lambda. o Something of the form {->X} is ambiguous between a function type and a lambda whenever X is also. So {->{->{->X}}} is ambiguous between a function type and a lambda. This is the state of BGGA 0.5 and the BGGA compiler has no trouble disambiguating during parsing. Cheers, Neal From jjb at google.com Tue Mar 2 09:55:59 2010 From: jjb at google.com (Joshua Bloch) Date: Tue, 2 Mar 2010 09:55:59 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003020910.04583.peter.levart@marand.si> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <6DAD8A9A-24E2-4C35-A5D1-E15B9B7457AD@googlemail.com> <201003020910.04583.peter.levart@marand.si> Message-ID: <17b2302a1003020955h4a6eedfcw58022bfa0614a228@mail.gmail.com> Peter, On Tue, Mar 2, 2010 at 12:10 AM, Peter Levart wrote: > > > > static > > > (T->(U throws X->V)) curry((T,U throws X->V) function) { > > > return (T t->(U u->function.(t,u))); > > > } > > > > > That's pretty good in my eyes - for these non-trivial types I think it's > much easier to follow than the equivalent code using the currently proposed > syntax. > Beauty is in the eye of the beholder. It doesn't look at all like Java to me, and that's a Cardinal when extending a language. Our primary goal is to design a facility that's recognizable and comfortable to current-day Java programmers. > > I also think that it is good that this syntax doesn't abuse '#' for yet > another thing. There's already non-java identifiers and method references > that use it. Adding function types and lambdas to the mix increases > confusion as everything looks similar. But the language doesn't have method references. And non-Java identifiers aren't supposed to occur in programs that humans will be reading, only in machine generated code. In sum, I don't find these arguments all that convincing. Josh From jjb at google.com Tue Mar 2 10:12:12 2010 From: jjb at google.com (Joshua Bloch) Date: Tue, 2 Mar 2010 10:12:12 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003021241.02792.peter.levart@marand.si> References: <201003021241.02792.peter.levart@marand.si> Message-ID: <17b2302a1003021012g5cf068q80d9188aeab5a217@mail.gmail.com> Peter, Ooops, sorry; I thought the last message I answered was your response to my query. On Tue, Mar 2, 2010 at 3:41 AM, Peter Levart wrote: > On Tuesday 02 March 2010 08:58:28 Joshua Bloch wrote: > > Peter, > > > > On Mon, Mar 1, 2010 at 11:49 PM, Peter Levart >wrote: > > > > > I think we don't need statement lambdas if we allow expression to be > > > preceeded by statements (like in block expression of CfJ0.6b): > > > > > > Lambda: > > > '(' FormalParameters_opt '->' Statements_opt Expression ')' > > > > > > for void lambdas "void" keyword could be defined as expression of type > > > void: > > > > > > (->void) lambda = (-> System.out.println("Hello!"); void); > > > > > > > Why do you like this better than the current proposal? > > > > Josh > > > > Regarding function types syntax I don't really have a preference to the > order of (parameter types, return type, throws types) but I think that a > syntax that composes well (nests) is better. In this regard the current > proposal is not the best of all alternatives. > I agree that it would be nice if we had something that nests better, and I'm totally open to suggestion. But this alternative comes with many downsides: surrounding a type in parens might appear tempting, but it really looks like a cast to current-day Java programmers. As per my previous e-mail, I'm all about designing a facility that is maximally readable, familiar, and non-threatening to current-day Java programmers. > > > > Regarding preference to expression lambdas, I think they provide a way to > avoid defining the meaning of "return" at present time. The 1st release of > lambdas in JDK7 could simply disallow "return". Experience gathered from the > milions of Java developers in comming years would help shape a decision of > what to do with "return" (be it local or transparent) for the next release > in JDK8 which could add statement lambdas as well. > I think you can probably guess how I feel about this argument. I believe that preserving the meaning of return to return a value from the function-object invocation (as per current-day use of SAM types) is the way to go. If, in a future release we elect support non-local returns, it will probably require a new keyword to clearly distinguish local and non-local returns. We should cross that bridge when/if we come to it, but in the meantime, it's our job to make the best possible lambda syntax and semantics, as per the charter of this project. Josh From john at milsson.nu Tue Mar 2 11:29:48 2010 From: john at milsson.nu (John Nilsson) Date: Tue, 2 Mar 2010 20:29:48 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003021012g5cf068q80d9188aeab5a217@mail.gmail.com> References: <201003021241.02792.peter.levart@marand.si> <17b2302a1003021012g5cf068q80d9188aeab5a217@mail.gmail.com> Message-ID: On Tue, Mar 2, 2010 at 7:12 PM, Joshua Bloch wrote: > non-threatening to current-day Java programmers. Which ones are that? The crowd who is still using Java 1.4 and are afraid of generics trying? Or the bunch who are actually capable of learning new things? BR, John From reinier at zwitserloot.com Tue Mar 2 17:09:18 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 3 Mar 2010 02:09:18 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003020849.54620.peter.levart@marand.si> References: <15e8b9d21002261748u77d29847ob56e4544263b5d1c@mail.gmail.com> <15e8b9d21003011542s3f4b1218iac6d7b129b63af85@mail.gmail.com> <560fb5ed1003011818u5534d0f1ye849134de26a27fb@mail.gmail.com> <201003020849.54620.peter.levart@marand.si> Message-ID: <560fb5ed1003021709s3981715hc4c81d15503eaa51@mail.gmail.com> Well, let's think about how people are going to format their lambdas. Given fact: The vast majority of java programmers block-brace everything, even trivial stuff. The following: if (someCondition) return false; is _far_ more rare compared to: if (someCondition) { return false; } without making a judgement call on the intelligence or lack thereof of so doggedly preferring braces, it seems rather obvious then that your average java programmer writing a multi-statement closure is rather obviously going to write it like so: stringList.forEach(#(String x) { System.out.println(x); y.registerKey(x); }); This also nicely solves the problem of a confusingly large amount of semicolons if you tried to one-liner all of this; your code would end in ";});" which looks weird, to say the least. However, if we go with your prefix-statements concept, you get: stringList.forEach(#(String x) ( System.out.println(x); y.registerKey(x); void )); exactly how this is an improvement is a mystery to me. The biggest issue I see with the status quo syntax is one-liners that return void. You might want to prefer to write something like: stringList.forEach(#(String x) {System.out.println(x)}); //note lack of semi-colon after println. or the same thing but with parens: stringList.forEach(#(String x) (System.out.println(x))); (though in this trivial case we're already seeing 3 closing parens, which means in more complex cases it's going to look like LISP!) either of which isn't, as far as I understand the status quo proposal, legal, because System.out.println(x) cannot function as an expression here, as returning "void" like this isn't allowed (and in java in general, "void" is not really a type as such. Some other languages treat it as the bottom type, java doesn't). Not adequately solving every single last corner case is _NOT_, as far as I'm concerned, a requirement for a java language feature to be added to the JLS, but perhaps someone has a good idea on how to solve this. Nevertheless, this: stringList.forEach(#(String x) { System.out.println(x); }); looks allright to me, and more to the point, given the proclivities of throwing braces around everything amongst the java rank-and-file, it'll look allright to them, even if it tends to look somewhat verbose to us lambda-dev readers. What you're essentially suggesting, and you should go all the way with it lest java becomes too inconsistent, is a new language construct: ExpressionGroup: '(' StatementsInGroup[opt] Expression ')' StatementsInGroup: Statement ';' StatementsInGroup[opt] in other words, if you allow that, then this should also be legal: int x = (System.out.println("Hello, World!"); 5); That's got all sorts of problems: - how are you even going to format this? - it treats the ';' as a separator, whereas everywhere else in java it *ISNT* a separator, it's a suffix for a statement. I know from personal experience that java's semi-colon policy is much easier to understand for beginning students that Pascal's, which does treat its closer symbols as separators most of the time, meaning, for example, that the last statement doesn't need one. In java, the last statement in a block *DOES* need a semi-colon, because it is *NOT* a separator. But in this expression group concept, it *IS* a separator. - What's the problem this solves? You lose some complexity in the JLS when defining closures, but you lose even more when you have to define a new construct "void" (as an expression), probably you have to redefine "void" itself as a legal type of an expression throughout the entire JLS instead of a placeholder for method return types. Right now you can *NOT* write: "return System.out.println("foo");" in a method that has 'void' as a return type, so right now "void" is *NOT* a type, at least, not like other types are. You'd have to change all of this for consistency. That's far more effort to change in the JLS than you save. Neal also suggested it for coin and it was shot down almost immediately. --Reinier Zwitserloot On Tue, Mar 2, 2010 at 8:49 AM, Peter Levart wrote: > I think we don't need statement lambdas if we allow expression to be > preceeded by statements (like in block expression of CfJ0.6b): > > Lambda: > '(' FormalParameters_opt '->' Statements_opt Expression ')' > > for void lambdas "void" keyword could be defined as expression of type > void: > > (->void) lambda = (-> System.out.println("Hello!"); void); > > > Regarding arrays of function types, this syntax: > > FunctionType: > '(' ParameterTypes_opt Throws_opt '->' ReturnType ')' > > is perfectly combinable with array type syntax. > > Peter > > On Tuesday 02 March 2010 03:18:30 Reinier Zwitserloot wrote: > > In regards to: > > > > (String x -> 3) > > > > What is this going to look like when the body of the closure is not a > single > > expression but a block? > > > > --Reinier Zwitserloot > > > From jp at hapra.at Mon Mar 8 09:25:09 2010 From: jp at hapra.at (Jakob Praher) Date: Mon, 08 Mar 2010 18:25:09 +0100 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B95325D.3020702@hapra.at> References: <4B95325D.3020702@hapra.at> Message-ID: <4B9532F5.9030702@hapra.at> This line Function echo = echoMethod.bind(this); should actually be Function echo = echoMethod.bind(myinstance); Jakob Praher schrieb: > Dear List, > > I was thinking much about the syntax of the upcoming language changes > regarding the introduction of > * first class functions > * first class function types > * lambda expressions ("closures") > > While IMHO the best would be to refactor certain aspects of the > language (e.g. blur the distinction between Statements and > Expressions, especially treat "blocks" as expressions, change the call > expressions to allow custom control flow constructs, ...). > > Since I am realistic in that such changes will not be doable for > version 7, I think one should seek orthogonality and consistency in > integrating these new constructs. > > I would suggest the following: > * Add a call operator (e.g. a special purpose "call" method) that can > be short-cutted to x() instead of x.call(...) > * Treat a function as an instance of java.lang.Function ArgT1, ..ArgTn> that implements this call operator > * Add a special keyword "lambda" for creating an instance of a > Function from a Block (this is in the tradition of "synchronized" and > friends): > Function square = lambda(int x) { return x*x ; } > > * Introduce a bind method that converts a method to its lamba form > (currying the this away): > class MyClass { String echo(String x ) { return x; } } > Method echoMethod = myinstance.getClass().getMethod("test"); > Function echo = echoMethod.bind(this); > System.out.println( echo("Hello") ); > System.out.println( echo.call("Hello") ); > > Some Reasons: > * Is IMHO more consitent with current Java > * Reflection concepts like Class, Method, ... are "magic VM" instances > too > * AtomicInteger.compareAndSet can be internally optimized to single > CAS instruction too > > What do you think about this? > > -- Jakob > > > > > > From neal at gafter.com Mon Mar 8 09:58:41 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 8 Mar 2010 09:58:41 -0800 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B9532F5.9030702@hapra.at> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> Message-ID: <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> Jakob- I did not see your original message, but I have some thoughts: o I do not agree that it is practical to blur the distinction between statement and expressions in Java's future. o The ability to 'shortcut" the call operator x.call(e) as x(e) raises some difficult issues with name lookup that have not yet been solved, which is why a different syntax is being considered. o Functions as interfaces is one option explored in detail in BGGA. The alternative of using MethodHandle is being considered for project lambda. o Currying and method references in the source should not require going through type-unsafe intermediaries such as reflection. Cheers, Neal On Mon, Mar 8, 2010 at 9:25 AM, Jakob Praher wrote: > This line > ? Function echo = echoMethod.bind(this); > should actually be > ? Function echo = echoMethod.bind(myinstance); > > Jakob Praher schrieb: >> >> Dear List, >> >> I was thinking much about the syntax of the upcoming language changes >> regarding the introduction of >> * first class functions >> * first class function types >> * lambda expressions ("closures") >> >> While IMHO the best would be to refactor certain aspects of the language >> (e.g. blur the distinction between Statements and Expressions, especially >> treat "blocks" as expressions, change the call expressions to allow custom >> control flow constructs, ...). >> >> Since I am realistic in that such changes will not be doable for version >> 7, I think one should seek orthogonality and consistency in integrating >> these new constructs. >> >> I would suggest the following: >> * Add a call operator (e.g. a special purpose "call" method) that can be >> short-cutted to x() instead of x.call(...) >> * Treat a function as an instance of java.lang.Function> ..ArgTn> that implements this call operator >> * Add a special keyword "lambda" for creating an instance of a Function >> from a Block (this is in the tradition of "synchronized" and friends): >> ? ?Function square = lambda(int x) { return x*x ; } >> >> * Introduce a bind method that converts a method to its lamba form >> (currying the this away): >> ? ?class MyClass { ?String echo(String x ) { return x; } } >> ? ?Method echoMethod = myinstance.getClass().getMethod("test"); >> ? ?Function echo = echoMethod.bind(this); >> ? ?System.out.println( echo("Hello") ); >> ? ?System.out.println( echo.call("Hello") ); >> >> Some Reasons: >> * Is IMHO more consitent with current Java >> * Reflection concepts like Class, Method, ... are "magic VM" instances too >> * AtomicInteger.compareAndSet can be internally optimized to single CAS >> instruction too >> >> What do you think about this? >> >> -- Jakob >> >> >> >> >> >> > > From jp at hapra.at Mon Mar 8 09:22:37 2010 From: jp at hapra.at (Jakob Praher) Date: Mon, 08 Mar 2010 18:22:37 +0100 Subject: call operator and orthogonality with existing VM internals Message-ID: <4B95325D.3020702@hapra.at> Dear List, I was thinking much about the syntax of the upcoming language changes regarding the introduction of * first class functions * first class function types * lambda expressions ("closures") While IMHO the best would be to refactor certain aspects of the language (e.g. blur the distinction between Statements and Expressions, especially treat "blocks" as expressions, change the call expressions to allow custom control flow constructs, ...). Since I am realistic in that such changes will not be doable for version 7, I think one should seek orthogonality and consistency in integrating these new constructs. I would suggest the following: * Add a call operator (e.g. a special purpose "call" method) that can be short-cutted to x() instead of x.call(...) * Treat a function as an instance of java.lang.Function that implements this call operator * Add a special keyword "lambda" for creating an instance of a Function from a Block (this is in the tradition of "synchronized" and friends): Function square = lambda(int x) { return x*x ; } * Introduce a bind method that converts a method to its lamba form (currying the this away): class MyClass { String echo(String x ) { return x; } } Method echoMethod = myinstance.getClass().getMethod("test"); Function echo = echoMethod.bind(this); System.out.println( echo("Hello") ); System.out.println( echo.call("Hello") ); Some Reasons: * Is IMHO more consitent with current Java * Reflection concepts like Class, Method, ... are "magic VM" instances too * AtomicInteger.compareAndSet can be internally optimized to single CAS instruction too What do you think about this? -- Jakob From serge.boulay at gmail.com Mon Mar 8 11:51:44 2010 From: serge.boulay at gmail.com (Serge Boulay) Date: Mon, 8 Mar 2010 14:51:44 -0500 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B95325D.3020702@hapra.at> References: <4B95325D.3020702@hapra.at> Message-ID: <855b507d1003081151w22cc37d5p88c4136cb090d8ae@mail.gmail.com> I do like the idea of the lambda keyword Function square = lambda(int x) { return x*x ; } and this would clearly distinguish it from the proposed method literals that use #. On Mon, Mar 8, 2010 at 12:22 PM, Jakob Praher wrote: > Dear List, > > I was thinking much about the syntax of the upcoming language changes > regarding the introduction of > * first class functions > * first class function types > * lambda expressions ("closures") > > While IMHO the best would be to refactor certain aspects of the language > (e.g. blur the distinction between Statements and Expressions, > especially treat "blocks" as expressions, change the call expressions to > allow custom control flow constructs, ...). > > Since I am realistic in that such changes will not be doable for version > 7, I think one should seek orthogonality and consistency in integrating > these new constructs. > > I would suggest the following: > * Add a call operator (e.g. a special purpose "call" method) that can be > short-cutted to x() instead of x.call(...) > * Treat a function as an instance of java.lang.Function ArgT1, ..ArgTn> that implements this call operator > * Add a special keyword "lambda" for creating an instance of a Function > from a Block (this is in the tradition of "synchronized" and friends): > Function square = lambda(int x) { return x*x ; } > > * Introduce a bind method that converts a method to its lamba form > (currying the this away): > class MyClass { String echo(String x ) { return x; } } > Method echoMethod = myinstance.getClass().getMethod("test"); > Function echo = echoMethod.bind(this); > System.out.println( echo("Hello") ); > System.out.println( echo.call("Hello") ); > > Some Reasons: > * Is IMHO more consitent with current Java > * Reflection concepts like Class, Method, ... are "magic VM" instances too > * AtomicInteger.compareAndSet can be internally optimized to single CAS > instruction too > > What do you think about this? > > -- Jakob > > > > > > > From jp at hapra.at Tue Mar 9 04:23:40 2010 From: jp at hapra.at (Jakob Praher) Date: Tue, 09 Mar 2010 13:23:40 +0100 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> Message-ID: <4B963DCC.5050100@hapra.at> Dear Neal, thanks for your reply. Neal Gafter schrieb: > Jakob- > > I did not see your original message, but I have some thoughts: Interesting that the mail itself did not hit the list. > > o I do not agree that it is practical to blur the distinction between > statement and expressions in Java's future. I think there is some dichotomy in language constructs due to the reason that features are piled on top of existing constructs. Project lambda basically allows you to take a block of statements (with bounded variables) as a callable object. So the philosophical issue is whether a block should be an expression. mySychronized( #(Object x) { ... } ) vs synchronized (x) { } I meant refactoring as a method to think about our axioms. I have to confess I am a little bit torn on the issue as well and I have not come up with a good solution to the problem. To me everything boils down to the point that we have to syntactically slight modified constructs that teach you the opposite (Blocks are statements, Lambdas are expressions) and also have constructs such as "synchronized" that also take blocks as arguments. > o The ability to 'shortcut" the call operator x.call(e) as x(e) raises > some difficult issues with name lookup that have not yet been solved, > which is why a different syntax is being considered. Do you have any details on that? I think another interesting idea would be that if an interface only declares one public method this public method name does not have to be used as a designator for the method call: E.g. interface Runnable { public void run() ; } Runnable r = ...; r(); Overloading could be an obstacle to be overcome in this scenario. But by defining "one method" as "one method whose signature matches a given call expression". E.g. interface RunnableWithOrWithoutArguments { public void run(Object o); public void run(); } RunnableWithOrWithoutArguments x = ?; x(); x(new String()); would both be unambigious. o Functions as interfaces is one option explored in detail in BGGA. > The alternative of using MethodHandle is being considered for project > lambda. What is your opinion on that? My motivation for functions as interface types is out of syntactic taste. In some way I would favor a joined effort with the dynamic extensions to Java. On another note: The lambda project (other than introducing a new way to represent function) will not introduce any new bytecode, right? E.g. Does a lambda object expose a method that can be invoked internally? (E.g. via invokedynamic and friends?). I will look at BGGA. The nice thing about function as interface the familiarity and compatibility with existing interfaces . The downside is that different arity is not expressible with current generics. But one could generate Function0...FunctionN > o Currying and method references in the source should not require > going through type-unsafe intermediaries such as reflection. > This was more for illustrative purposes. I chose bind not especially for currying but for binding a lambda to an existing method with reflection. FCM addresses this issue more type safe. One could do currying using FCM and lambdas: Function2 method = MyClass#echo; Function1 f = lambda(String phrase) { return method(new MyClass(),phrase); } When should one function be subtype of another funciton? Does covariancy is an issue for that? Something like that is also harder to express with interface types. -- Jakob > Cheers, > Neal > > On Mon, Mar 8, 2010 at 9:25 AM, Jakob Praher wrote: >> This line >> Function echo = echoMethod.bind(this); >> should actually be >> Function echo = echoMethod.bind(myinstance); >> >> Jakob Praher schrieb: >>> Dear List, >>> >>> I was thinking much about the syntax of the upcoming language changes >>> regarding the introduction of >>> * first class functions >>> * first class function types >>> * lambda expressions ("closures") >>> >>> While IMHO the best would be to refactor certain aspects of the language >>> (e.g. blur the distinction between Statements and Expressions, especially >>> treat "blocks" as expressions, change the call expressions to allow custom >>> control flow constructs, ...). >>> >>> Since I am realistic in that such changes will not be doable for version >>> 7, I think one should seek orthogonality and consistency in integrating >>> these new constructs. >>> >>> I would suggest the following: >>> * Add a call operator (e.g. a special purpose "call" method) that can be >>> short-cutted to x() instead of x.call(...) >>> * Treat a function as an instance of java.lang.Function>> ..ArgTn> that implements this call operator >>> * Add a special keyword "lambda" for creating an instance of a Function >>> from a Block (this is in the tradition of "synchronized" and friends): >>> Function square = lambda(int x) { return x*x ; } >>> >>> * Introduce a bind method that converts a method to its lamba form >>> (currying the this away): >>> class MyClass { String echo(String x ) { return x; } } >>> Method echoMethod = myinstance.getClass().getMethod("test"); >>> Function echo = echoMethod.bind(this); >>> System.out.println( echo("Hello") ); >>> System.out.println( echo.call("Hello") ); >>> >>> Some Reasons: >>> * Is IMHO more consitent with current Java >>> * Reflection concepts like Class, Method, ... are "magic VM" instances too >>> * AtomicInteger.compareAndSet can be internally optimized to single CAS >>> instruction too >>> >>> What do you think about this? >>> >>> -- Jakob >>> >>> >>> >>> >>> >>> >> > From neal at gafter.com Tue Mar 9 08:47:20 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 9 Mar 2010 08:47:20 -0800 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B963DCC.5050100@hapra.at> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> <4B963DCC.5050100@hapra.at> Message-ID: <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> On Tue, Mar 9, 2010 at 4:23 AM, Jakob Praher wrote: >> o The ability to 'shortcut" the call operator x.call(e) as x(e) raises >> some difficult issues with name lookup that have not yet been solved, >> which is why a different syntax is being considered. > > Do you have any details on that? The name lookup issues have been discussed on this list, so you'll find some details in the archives. To summarize, in an expression x.y(z), the name y is looked up from among the method names of x's type. That means a field named y won't be found. We cannot change that in a way that changes the behavior of existing programs. > I think another interesting idea would be that if an interface only declares > one public method this public method name does not have to be used as a > designator for the method call: That would break existing programs, because some existing program could have both a method named r and a field named r of type Runnable. > o Functions as interfaces is one option explored in detail in BGGA. >> >> The alternative of using MethodHandle is being considered for project >> lambda. > > What is your opinion on that? My motivation for functions as interface types > is out of syntactic taste. I think either one is a viable option, though some changes to MethodReference are required (to support variance) before they can be used for this. > When should one function be subtype of another funciton? > Does covariancy is an issue for that? Something like that is also harder to > express with interface types. BGGA manages to handle function types with covariant returns and contravariant argument types by treating then as instances of generic interfaces using wildcards. From jp at hapra.at Tue Mar 9 09:24:40 2010 From: jp at hapra.at (Jakob Praher) Date: Tue, 09 Mar 2010 18:24:40 +0100 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> <4B963DCC.5050100@hapra.at> <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> Message-ID: <4B968458.2010702@hapra.at> Neal Gafter schrieb: > On Tue, Mar 9, 2010 at 4:23 AM, Jakob Praher wrote: > > BGGA manages to handle function types with covariant returns and > contravariant argument types by treating then as instances of generic > interfaces using wildcards. > Makes sense. Thought about that but had problems since one has to specify that in the formal parameters. This relation is not (easily) encodable in the type definition itself. Function1 (leaving out exceptions) has to be used as formal parameters otherwise no "subtyping will be posisble". This is also what I meant that here the out-of-box usablity of function types (as interfaces) is limited. (Was this also one of the reason that you introduced the {..=>..) syntax?) -- Jakob. From neal at gafter.com Tue Mar 9 09:57:32 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 9 Mar 2010 09:57:32 -0800 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B968458.2010702@hapra.at> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> <4B963DCC.5050100@hapra.at> <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> <4B968458.2010702@hapra.at> Message-ID: <15e8b9d21003090957v69a5b4c5n644ec8d2ebdddad8@mail.gmail.com> On Tue, Mar 9, 2010 at 9:24 AM, Jakob Praher wrote: >> ?BGGA manages to handle function types with covariant returns and >> contravariant argument types by treating then as instances of generic >> interfaces using wildcards. > > Makes sense. Thought about that but had problems since one has to specify > that in the formal parameters. This relation is not (easily) encodable in > the type definition itself. Function1 ?(leaving out > exceptions) has to be used as formal parameters otherwise no "subtyping will > be posisble". Which is why BGGA provides a special syntax for function types that inserts the wildcards for you. > This is also what I meant that here the out-of-box usablity of function > types (as interfaces) is limited. (Was this also one of the reason that you > introduced the {..=>..) syntax?) Exactly. From reinier at zwitserloot.com Tue Mar 9 13:28:50 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 9 Mar 2010 22:28:50 +0100 Subject: Primitives in Generics proposal. Message-ID: <560fb5ed1003091328k7cde27fcn9c14d9f1881b30b2@mail.gmail.com> As Stephen Colebourne already suggested, the various problems with function types can be sidestepped rather simply by sticking purely with (SAM) type names, immediately fitting any lambda to an appropriate SAM type. However, to feasibly go this route, generics _need_ to be able to work with primitive types, in order to reduce ParallelArray's 132 SAM types in Ops down to a nice lean 8. I've written up a proposal to get the discussion going. If indeed the existence of such a proposal results in a much simpler Project Lambda, then the time saved implementing Project Lambda can be used to implement this idea. It should go without saying that allowing primitives in generics would be a great feature for JDK7 on its own. The canonical version that will be updated and is nice on the eyes can be found here: http://projectlombok.org/primitive_generics/ but in the interests of saving all discussion in one thread I've pasted the markdown source of v1.0 below. Happy reading! # Primitives in generics proposal v1.0 by Reinier Zwitserloot ## §1 Preamble and necessity of the feature The goal of this proposal is to allow primitives in generics. To simplify the proposal, `int` is used in all examples and in all text. All the other 7 primitive types are of course also allowed as type arguments. In particular, a closure strategy for JDK7's [Project Lambda][] to always _box_ any closure into a so-called SAM type is a far more realistic option if the used SAM types can accept primitives in their generics. (a type that contains exactly 1 abstract method, usually an interface. For example, `java.util.Comparator` is a SAM type. So is `java.lang.Runnable`). For example, [jsr166y-extra - Parallel Arrays][jsr166yx], the standard usecase example for Project Lambda, currently lists 132 SAM interface types in its [Ops]( http://gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/Ops.html) container class, but most of those are simply to provide a primitive-based version of a few central concepts. If primitive generics were possible, this list of 132 would be reduced to a much more manageable set. To be precise: Ops.Op Ops.BinaryOp Ops.Predicate Ops.BinaryPredicate Ops.Procedure Ops.Generator Ops.Reducer extends BinaryOp java.util.Comparator Ops.Action These names are more meaningful than their equivalent purely structural function type constructs. For example, jsr166yx includes the concept of a `Ops.Reducer` even though the signature of a reducer is 100% equivalent to the more general `Op` class. It is self-evident then that the designers of jsr166yx find this kind of purely name-based distinction important enough to dedicate 4 of Ops' 132 SAM types to it even though they didn't have to. Furthermore, as the inclusion of `java.util.Comparator` foreshadowed, sticking with names for function types fits better with existing java code. jsr166yx as it stands uses `java.util`'s version of Comparator for its Object based `ParallelArray` but defined its own versions for the primitives, such as `Ops.LongComparator`. If function types were introduced instead, then jsr166yx would obviously replace its `Ops.LongComparator` with `#int(long, long)` but it would face a dilemma for its `Object` based `ParallelArray`: Should it take `#int(T, T)`, should it take `java.util.Comparator`, or should it take both? None of these three options are fully consistent. This isn't a rare coincidence; the amount of SAM types that are in active use across the java community is staggering, and introducing function types to solve the primitives problem is going to introduce a lot of inconsistency as APIs evolve to accept closures but keep their old SAM based methods for backwards compatibility. The solution is as clear as it is obvious: Make primitives allowable as type argument. Together with a relatively minor and proven (by JRockit which already includes it) JVM optimization, both the API and the performance issues can be solved. As a secondary step, one could start questioning if, once this feature has been added, function types are even necessary. As recent traffic on the [Project Lambda mailing list]( http://mail.openjdk.java.net/mailman/listinfo/lambda-dev) has indicated, there are a host of issues with function types, from syntax ambiguities to problems around allowing arrays of function types. By sticking with SAM types, no new ideas are introduced for the java community to learn; they presumably already know that for example the expression `new Comparator[10]` is not legal. Last but certainly not least: Primitives as type arguments are a great feature for the java language all by themselves and not only as a part of a closure proposal. For example, if this proposal is implemented in JDK7, the following could be allowed: `List intList = new IntList();` and be virtually as fast as a purely `int` array based list implementation such as the ones that can be found in [GNU Trove]( http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntArrayList.html), but which is API compatible with `java.util.List`. This v1.0 of the proposal does not highlight which sections of the JLS are involved or need to be changed. Its primary intention is to start a discussion, explore the feasibility, if it has clear solutions for all potential issues, and if it can lead to a simplification of Project Lambda, thus freeing up enough time in the JDK7 schedule to implement it. [Project Lambda]: http://openjdk.java.net/projects/lambda/ "Project Lambda Mailing List" [jsr166yx]: http://gee.cs.oswego.edu/dl/concurrency-interest/ "jsr166y - Parallel Arrays" ## §2 Proposal ### §2.1 Type Variables Type variables are the `T` in `public class Foo {}`. Type variables can only include actual types in their bounds, such as ``. As `T extends int` doesn't really convey a useful construct, we simply won't allow it. This means type variables themselves don't have to change at all. ### §2.2 Type Arguments Type Arguments come in two flavours: Just the type, as in: `List`, or as a bound, such as `List`. As primitive types don't really have subtype relations, there is again not much sense in allowing either `List` or `List`. It is therefore not allowed; *only* `List` would be legal. To be precise, `List>` would be allowed, but `List>` would not be. ### §2.3 Syntax Sugar The JVM barely supports generics (instances don't preserve their type arguments, and method signatures don't either), and changing the JVM is a major undertaking so this proposal does not include any required changes to the JVM. Therefore, Something like `List x;` is effectively syntax sugar similar to how `List x;` is effectively syntax sugar. ### §2.4 Legality of primitive type arguments. A primitive can be bound to a type argument anywhere its wrapped type would be legal. Therefore, `int` is valid when the bound is `T extends Number`, but it would not be if the bound was, for example, `T extends InputStream`. ### §2.5 The *typearg_int* imaginary type. Anytime a primitive type is encountered as a type argument, the compiler needs to keep track of the notion that the primitive type is used as type bound. For example, the compiler will usually have to inject synthetic methods that replace the primitive type with its wrapper type. To help clarify the actions that the compiler needs to take, we'll call any `int` that appears in a location where it is being used to fit a type variable as the imaginary `typearg_int` type. This isn't a real type, just a virtual construct of the compiler. This concept already exists in java. If, for example, you write the following code: public abstract class Example implements List { @Override public boolean void add(String x) { return true; } } and inspect the class produced by javac, you'll notice 2, and not 1, `add` method; you'll see `add(Object)` as well as `add(String)` in the generated class file. The `add(Object)` simply passes the call to the `add(String x)` method, which involves a type cast. For primitive types, this concept is no different: public abstract class Example implements List { @Override public boolean void add(int x) { return true; } } would result in not just `add(int)` but also `add(Object)` which simply passes the call on. In addition to a type cast (to `java.lang.Integer`), this wrapper method will also auto-unbox the object. ### Sugar #### §2.6 Field Read Anytime a field of type "int" is read, the compiler emits bytecode: GETFIELD/GETSTATIC "java/awt/Point" "x" "I" However, if a field of type "typearg_int" is read, it is unboxed first, so, the compiler emits: GETFIELD/GETSTATIC "java/awt/Point" "x" "Ljava/lang/Object;" INVOKEVIRTUAL "java/lang/Integer" "intValue" "()I" In other words, the field is assumed to be of the erased typevar's type (Object in the example, but could also be e.g. `Number`), is assumed to contain an `Integer` object, and `intValue()` is called on it. This act may result in the usual `ClassCastException` if heap pollution has occurred, but can additionally also result in a `NullPointerException`, even without heap pollution. This is analogous to auto-unboxing causing an NPE, which is in the current Java6 also possible even if heap pollution has not taken place. The java community has embraced autoboxing/unboxing even with this shortcoming in the typing system, hence this similar case, which is not readily solvable, can be considered the same way: A problem, but not a show-stopper. #### §2.7 Field Write Analogous to field read; instead of generating a `PUTFIELD` of type "I", the erased typevar's type is used instead, and a call to `INVOKESTATIC "java/lang/Integer" "valueOf" "(I)Ljava/lang/Integer;"` is inserted before the `PUTFIELD` instruction. Unlike the field read, there's no NullPointerException issue here. #### §2.8 Creating a field with a "typearg_int" type. This isn't possible; Fields cannot be overridden, they can only be shadowed. Fields *can* of course be defined as having a type variable as type, but a type variable's actual type is unknown. For example: public class Foo { T x; } The `T` can be anything and is in practice erased to `java.lang.Object`. This erasure will not change because of this proposal, and an erasure to a primitive type isn't possible, because `` is not legal. #### §2.9 Method invocation When invoking a method where one or more parameters is of type `typearg_int`, then during the creation of the bytecode to load the parameters on the stack, an `INVOKESTATIC` to `Integer.valueOf(int)` is generated to box the primitive. Similarly, the signature generated in the `INVOKEVIRTUAL`/`INVOKESTATIC` call is of the erased typevar's type and not `I`. If the invoked method's return type is of type `typearg_int`, the return type in the signature is as usual replaced with the erased typevar's type. Unless the return value is discarded because the method invocation appears as expression statement, an `INVOKEVIRTUAL` call to `Integer.intValue()` is inserted immediately after the `INVOKEVIRTUAL`/`INVOKESTATIC` instruction. #### §2.10 Method declaration (Preamble) This part of the spec gets somewhat complicated, but this complication is not new! For example, imagine the following two types: public class A { void foo(T in) {} } public class B extends A { void foo(String in) {} } The current javac compiler solves this scenario by generating a synthetic wrapper with the signature: `void foo(Object)`, as `A`'s `foo` method has that erased type (`Object` is `T`'s type bound in class `A`). This synthetic method wraps the call to `B`. You can actually see this in action by looking at the stack trace you get when you throw an exception from `B.foo` and then calling it via: `A x = new B(); x.foo("");` The current java gets even more complicated if the supertype contains both `void foo(T)` and `void foo(String)`, which is of course legal as `T` erases to `Object`, not `String`. When defining `void foo(String)` in `B`, *BOTH* methods are overridden. Furthermore, trying to call `foo("")` on a variable of type `A` is not possible; a *this call is ambiguous* error is generated. This error cannot be avoided by casting the argument; only by casting the receiver (an instance of `A`) to a raw type can `foo` even be called in such a circumstance. The same problems occur when primitives are legal type bounds for type variables, and the same solutions suffice as well. There is some friction here, as the above java puzzler-esque exercise shows, but I'm not aware of any proposal for e.g. Project Coin to adress this problem, and thus one can safely conclude that this oddity is not that important. #### §2.11 Method Declaration (parameter) Let's say we have: public abstract class IntList implements List { public boolean add(int v) {return false;} } In this case, both the actual method is generated, as well as a synthetic method where every `typearg_int` is replaced with `Ljava/lang/Object;` (the erased type of typevar), i.e. both of these: add(I)Z add(Ljava/lang/Object;)Z are generated, with the second method typecasting its argument to `Integer`, unboxing it, and calling the first. Both `ClassCastException` and `NullPointerException` can occur as part of this operation, but the former only if heap pollution has taken place. Note there is no risk of an explosion of method signatures when a large number of `typearg_int` typed parameters show up. In a hypothetical method `add(T1 a, T2 b, T3 c)` with all 3 parameters a type variable, when all type variables are bound to a primitive type, then only two methods are generated: all 3 as primitive, and all 3 as wrapper type. Entirely analogous to the convoluted example at the beginning of this section, if this method is accessed as a `List`, the wrapper type version will be called, but code that works directly with the `IntList` type will generate a call to the primitive version. #### §2.12 Method Declaration (return type) Let's say we have: public abstract class IntList implements List { public int get(int idx) {return 0;} } In this case, again two versions are generated: get(I)I get(I)Ljava/lang/Object; Where `Object` comes from the erased type of this particular version of `typearg_int`. The second method simply calls on the first, boxes the result, and returns that. If a method contains both `typearg_int` in its parameter list as well as its return type, still only 2 methods are produced; one with all-primitives, and one with all-wrappers. The wrapper will unbox parameters and box the returned value. ### §2.13 The JRockit gambit It is virtually impossible to make something like this: List list = new ArrayList(); as efficient as an `int[]` without reification; `ArrayList`'s implementation creates an `Object[]` to store the list's elements in, and once it does this, the performance game is automatically lost - it must create an `int[]` array to get performance that is comparable to the performance of a raw `int` array. However, it couldn't possibly do this; when `ArrayList`'s constructor is called, its type parameter has been erased, so `ArrayList` simply cannot tell what kind of array it should make. However, all hope is not lost here, as this can be made quite efficient: List list = new IntArrayList(); or, to avoid up to 8 new classes in java.util, these specialized classes can be turned into inner classes of ArrayList, and ArrayList can gain a new "static" constructor: List list = ArrayList.with(int.class); The above example is poor man's reification: This way ArrayList's "with" static method can in fact create a new IntArrayList by runtime-inspecting the `int.class` parameter. However, even with the receiver (`IntArrayList`) being specifically built with the `int` primitive type in mind, and the caller (the one that declared `List list`) also operating solely on the primitives level, the above compilation strategy still means that the following code: list.add(10); results in the following bytecode: ICONST 10 INVOKESTATIC java/lang/Integer valueOf(I)Ljava/lang/Integer; INVOKEVIRTUAL java/util/List add(Ljava/lang/Object;)Z .... execution moves to `IntArrayList`'s code INVOKEVIRTUAL java/lang/Integer intValue()I INVOKEVIRTUAL java/util/IntArrayList add(I)Z .... The hotspot compiler will eventually inline the static call and the last 2 calls (as they are to small final methods), but nevertheless there's an object on the heap involved (the boxed integer), and two calls, even if inlined. However, the JRockit VM already eliminates sequential box/unbox calls even across invocations, which eliminates the heap object entirely. Together with inlining the pass-through call from add(Object) to add(int) this call is then just as fast as calling the *GNU Trove* `TIntArrayList`. See < http://blogs.oracle.com/ohrstrom/2009/05/pulling_a_machine_code_rabbit.html> for a treatise on how the JRockit VM handles eliminating sequential box/unbox operations. In situations where either the receiver (such as `java.util.ArrayList`) or the sender (some generic code that created a new list of it's own type variable `E`) is not working exclusively with `int` this optimization obviously won't work, _but_, this optimization would be impossible without at least reification, which is not feasible for JDK7. ### §2.14 Generics Conversion A type such as `Map` can be treated as a `Map` implicitly. The same property is granted to primitives; a primitive will readily convert to its wrapper type, which includes conversion to a (bound) wildcard as `Integer` has a place in the type hierarchy. In other words, a `Map` will implicitly convert to a `Map`, for example. This leads automatically to a dilemma; it means `List` can be treated as a `List`, and in that way, `null` can be added to this list which isn't technically compatible with primitives, and as a result, treating this list as a `List` again can result in a `NullPointerException`. This type conversion feels like autoboxing/unboxing which suffers from the same problem, and as covered this omission in the type system has been deemed acceptable before. As has been stated, `int` as a type bound is legal anywhere `Integer` would be, which implies that converting from for example `List` to `List` is also legal. ### §2.15 The benefit to the java community - recap Even without the JRockit optimization (which can at any time be added without requiring changes to this spec, which is focussed on the JLS and the compiler, and not the VM), this proposal is highly beneficial to the java community. Generified libraries virtually never offer primitive-optimized versions. For example, there is no ArrayList-like class for primitive ints in the java runtime; one would have to reach for third party libraries such as GNU Trove to find them. The large amount of code duplication that is required to produce a primitive-optimized version for all 8 primitive types is also very inpractical. It is clear, then, that the java community has decided to accept the performance penalty, and more problematically, the readability penalty, by choosing to use for example `List`. The readily available alternative, arrays, are continuously problematic in new proposals, as they don't work well together with generics and have different variance rules. This proposal would also help greatly in APIs which are designed with primitive arrays in mind. For example, the java.util.Arrays class has a utility method to sort an int[], but only by the natural order of integers. There is no `Comparator` based method for `int[]` in `java.util.Arrays`; there is only such a method for sorting `T[]`, and `T` can currently only stand for non-primitive types. With this feature, the following code could be legal: int[] array = {1, -3, 2, 8, 6}; Arrays.sort(array, new Comparator { public int compare(int a, int b) { a = Math.abs(a); b = Math.abs(b); return a < b ? -1 : a > b ? 1 : 0; } }); or, with closure support: Arrays.sort(array, #(int a, int b) { a = Math.abs(a); b = Math.abs(b); return a < b ? -1 : a > b ? 1 : 0; }); In other words, convenient syntax, fast execution, while *keeping* the `Comparator` concept. Comparator cannot obviously be removed (it would not be backwards compatible), and it would be inconsistent for the sorting APIs to work with `Comparator` when sorting Objects, but to work with `#int(int, int)` closures when trying to sort an array of primitive ints. ### §3 Curses! What about arrays! There's one case that this proposal has not yet covered: What happens when `typearg_int` is used in an array? Let's say we have: public class Foo { protected T[] array = null; public abstract void method(T[] param); public abstract T[] returnType(); } What would happen if we tried to write: public class Bar extends Foo { @Override public void method(int[] param) { this.array = param; } @Override public int[] returnType() { return param; } } This question seems academic, in that generics and arrays almost never meet, but that isn't quite true: `java.util.Collection` itself contains `public abstract T[] toList(T[] in);`. It is important to realize that because arrays and generics are already convoluted when used together in java6, the `T` in that signature is not related to the `E` of List itself (the `E` in `public interface Collection`!). For usage in method declarations the wrapper methods can create a new array and copy each element, autoboxing/unboxing on the way. This is mind-bogglingly inefficient, but it is simple. In practice the authors strongly suggest the implementer of `IntArrayList` write a specific method to get a straight `int[]` array without this convolution which obviously cannot be optimized by the VM the way a single `int` to/from `Integer` conversion can be. For array access, the proposal suggests treating this concept as extremely rare and thus coming up with the simplest thing that could possibly work: Access to the array (read/write) is allowed and involves boxing as usual, but a reference to `Foo.array` itself will simply remain its erased type and emits a warning. Therefore: public abstract class Bar extends Foo { void test() { Object[] o = array; //warning but legal int[] p = array; //error } } Nevertheless this concept introduces an API incompatibility: The javadoc for `toList` states that if the input array has enough room, the same array will be returned, and this cannot of course be done if the input array is first number-for-number copied into a `Object[]` array, and then after the copy operation has completed, this array is translated back to `int[]`. This proposal offers no solution to this dilemma. It can only note that as `int` is currently illegal in generics, it is technically backwards compatible to add a note to the javadoc that explains the same array is *not* returned even if it has enough room if the type bound is a primitive. It also shows a gap in the API of a hypothetical `IntArrayList`: The signature (as mandated by the `Collection` interface) must be `public T[] toArray(T[] in)`, and as `T[]`'s erasure, which is `Object[]`, is not compatible with `int[]`, this method cannot be made fast even for a specific subtype such as `IntArrayList`. This proposal offers no pragmatic solution other than to create a custom method in `IntArrayList` as well as a static utility method in `java.util.Collections` that can translate any list to `int[]`, which uses an instanceof check to pick up `java.util.ArrayList.IntArrayList`s special method and use that. The second issue raised is, in `public T[] toArray(T[] in)`, what happens if the calling code ends up binding `int` to `T`? This is a particularly painful process: Javac needs to generate the conversion from `int[]` to `Integer[]` prior to calling the method, and then the method will most likely convert back to `int[]`, and on the return phase the same double convert occurs for a grand total of 4 conversions. To avoid accidental triggering of this potentially very slow operation, a warning should be emitted anytime the compiler generates conversion code to convert a primitive array to a non-primitive array in order to fit with the erased signature of an invoked method. (For fields, as mentioned, the arrays remain their erased type, and an attempt to treat them as primitive array results in an error). From jp at hapra.at Tue Mar 9 15:22:41 2010 From: jp at hapra.at (Jakob Praher) Date: Wed, 10 Mar 2010 00:22:41 +0100 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <15e8b9d21003090957v69a5b4c5n644ec8d2ebdddad8@mail.gmail.com> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> <4B963DCC.5050100@hapra.at> <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> <4B968458.2010702@hapra.at> <15e8b9d21003090957v69a5b4c5n644ec8d2ebdddad8@mail.gmail.com> Message-ID: <4B96D841.9080805@hapra.at> Neal Gafter wrote: > On Tue, Mar 9, 2010 at 9:24 AM, Jakob Praher wrote: > > Which is why BGGA provides a special syntax for function types that > inserts the wildcards for you. > > When talking about Java on the whole (not the feature of adding function types), it might make sense to add support for covariant/contravariant annotations on types? Maybe it is enough to be able to use wildcards inside interface defintions: For instance interface Function1 { ... } would just mean that every usage of Function1 is replaced by Function1. The wildcards are stored in the type itself. It might not make sense to you to use exactly wildcards in the type definition this way, but I did not want to introduce a new syntax. This checks are done by the compiler (due to type erasure). There might be a better way to express this yet other than that the implementation could be done. Given that throws had to be added if the BGGA route would be taken (no?), was there any compelling reason not to consider variance qulifiers in type declarations? IMHO the big plus is that interface types are concise again. And the feature could be used in general. I also see no difference if every type of a function is automatically translated to have wildcards. And if I may add wildcards arbitrarily in type declarations I do not think it is dangerous to declare them generically in the type definition. Scala takes a similar route and allows variance annotations on generic types. There are some additional checks such that the type declaring the annotations must conform to covariance and contravariance. See chapter 4 section 5 of the Scala Language Specification [1]. -- Jakob [1] - http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf From neal at gafter.com Tue Mar 9 16:57:17 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 9 Mar 2010 16:57:17 -0800 Subject: Primitives in Generics proposal. In-Reply-To: <560fb5ed1003091328k7cde27fcn9c14d9f1881b30b2@mail.gmail.com> References: <560fb5ed1003091328k7cde27fcn9c14d9f1881b30b2@mail.gmail.com> Message-ID: <15e8b9d21003091657x1d715adfo5464518eea8a3070@mail.gmail.com> Reinier- An interesting idea, but unfortunately it is far larger in scope than project lambda, and requires a much deeper and more formal design of the type system impact. A type parameter implicitly "extends Object", but primitives do not. There are a few fatal flaws in your suggested approaches. First, subtype operations need to preserve reference identity, for reasons discussed earlier. Your plan to convert int[] to Integer[] and back again undermines that. Second, the boxing conversions blur but do not erase the distinction between primitives and reference types. You are simply incorrect when you say that primitives do not have subtypes. byte is a subtype of long but Byte is not a subtype of Long. Third, you cannot forbid primitives as bounds, even if primitives are considered invariant for the purposes of generics, because type parameters can be used as bounds too. Arrays of primitives are not syntactically allowed as bounds, but that is a syntactic restriction only, as type parameters can be primitive-array types, and type parameters can be bounds. It is hard to see how this can be implemented without at least partially reifying generics, as the bytecode to handle primitives differs from the code to handle reference types. Java has separate compilation and runtime binding, exposed in the language as "binary compatibility"; to support that, the VM must generate specializations at runtime. Cheers, Neal On Tue, Mar 9, 2010 at 1:28 PM, Reinier Zwitserloot wrote: > As Stephen Colebourne already suggested, the various problems with function > types can be sidestepped rather simply by sticking purely with (SAM) type > names, immediately fitting any lambda to an appropriate SAM type. However, > to feasibly go this route, generics _need_ to be able to work with primitive > types, in order to reduce ParallelArray's 132 SAM types in Ops down to a > nice lean 8. > > I've written up a proposal to get the discussion going. If indeed the > existence of such a proposal results in a much simpler Project Lambda, then > the time saved implementing Project Lambda can be used to implement this > idea. It should go without saying that allowing primitives in generics would > be a great feature for JDK7 on its own. > > The canonical version that will be updated and is nice on the eyes can be > found here: > > http://projectlombok.org/primitive_generics/ > > > but in the interests of saving all discussion in one thread I've pasted the > markdown source of v1.0 below. > > Happy reading! > > > # Primitives in generics proposal > > v1.0 > > by Reinier Zwitserloot > > > ## §1 Preamble and necessity of the feature > > The goal of this proposal is to allow primitives in generics. To simplify > the proposal, `int` is used in all examples and in all text. All the other 7 > primitive types are of course also allowed as type arguments. In particular, > a closure strategy for JDK7's [Project Lambda][] to always _box_ any closure > into a so-called SAM type is a far more realistic option if the used SAM > types can accept primitives in their generics. ?(a type that contains > exactly 1 abstract method, usually an interface. For example, > `java.util.Comparator` is a SAM type. So is `java.lang.Runnable`). For > example, [jsr166y-extra - Parallel Arrays][jsr166yx], the standard usecase > example for Project Lambda, currently lists 132 SAM interface types in its > [Ops]( > http://gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/Ops.html) > container class, but most of those are simply to provide a primitive-based > version of a few central concepts. If primitive generics were possible, this > list of 132 would be reduced to a much more manageable set. To be precise: > > ? ?Ops.Op > ? ?Ops.BinaryOp > ? ?Ops.Predicate > ? ?Ops.BinaryPredicate > ? ?Ops.Procedure > ? ?Ops.Generator > ? ?Ops.Reducer extends BinaryOp > ? ?java.util.Comparator > ? ?Ops.Action > > These names are more meaningful than their equivalent purely structural > function type constructs. For example, jsr166yx includes the concept of a > `Ops.Reducer` even though the signature of a reducer is 100% equivalent to > the more general `Op` class. It is self-evident then that the designers of > jsr166yx find this kind of purely name-based distinction important enough to > dedicate 4 of Ops' 132 SAM types to it even though they didn't have to. > > Furthermore, as the inclusion of `java.util.Comparator` foreshadowed, > sticking with names for function types fits better with existing java code. > jsr166yx as it stands uses `java.util`'s version of Comparator for its > Object based `ParallelArray` but defined its own versions for the > primitives, such as `Ops.LongComparator`. If function types were introduced > instead, then jsr166yx would obviously replace its `Ops.LongComparator` with > `#int(long, long)` but it would face a dilemma for its `Object` based > `ParallelArray`: Should it take `#int(T, T)`, should it take > `java.util.Comparator`, or should it take both? None of these three > options are fully consistent. This isn't a rare coincidence; the amount of > SAM types that are in active use across the java community is staggering, > and introducing function types to solve the primitives problem is going to > introduce a lot of inconsistency as APIs evolve to accept closures but keep > their old SAM based methods for backwards compatibility. > > The solution is as clear as it is obvious: Make primitives allowable as type > argument. Together with a relatively minor and proven (by JRockit which > already includes it) JVM optimization, both the API and the performance > issues can be solved. > > As a secondary step, one could start questioning if, once this feature has > been added, function types are even necessary. As recent traffic on the > [Project Lambda mailing list]( > http://mail.openjdk.java.net/mailman/listinfo/lambda-dev) has indicated, > there are a host of issues with function types, from syntax ambiguities to > problems around allowing arrays of function types. By sticking with SAM > types, no new ideas are introduced for the java community to learn; they > presumably already know that for example the expression `new > Comparator[10]` is not legal. > > Last but certainly not least: Primitives as type arguments are a great > feature for the java language all by themselves and not only as a part of a > closure proposal. For example, if this proposal is implemented in JDK7, the > following could be allowed: `List intList = new IntList();` and be > virtually as fast as a purely `int` array based list implementation such as > the ones that can be found in [GNU Trove]( > http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntArrayList.html), but > which is API compatible with `java.util.List`. > > This v1.0 of the proposal does not highlight which sections of the JLS are > involved or need to be changed. Its primary intention is to start a > discussion, explore the feasibility, if it has clear solutions for all > potential issues, and if it can lead to a simplification of Project Lambda, > thus freeing up enough time in the JDK7 schedule to implement it. > > > [Project Lambda]: http://openjdk.java.net/projects/lambda/ "Project Lambda > Mailing List" > [jsr166yx]: http://gee.cs.oswego.edu/dl/concurrency-interest/ "jsr166y - > Parallel Arrays" > > ## §2 Proposal > > ### §2.1 Type Variables > > Type variables are the `T` in `public class Foo {}`. Type variables can > only include actual types in their bounds, such as ``. As > `T extends int` doesn't really convey a useful construct, we simply won't > allow it. This means type variables themselves don't have to change at all. > > ### §2.2 Type Arguments > > Type Arguments come in two flavours: Just the type, as in: `List`, > or as a bound, such as `List`. As primitive types don't > really have subtype relations, there is again not much sense in allowing > either `List` or `List`. It is therefore not > allowed; *only* `List` would be legal. To be precise, `List Set>` would be allowed, but `List>` would not be. > > ### §2.3 Syntax Sugar > > The JVM barely supports generics (instances don't preserve their type > arguments, and method signatures don't either), and changing the JVM is a > major undertaking so this proposal does not include any required changes to > the JVM. Therefore, Something like `List x;` is effectively syntax > sugar similar to how `List x;` is effectively syntax sugar. > > ### §2.4 Legality of primitive type arguments. > > A primitive can be bound to a type argument anywhere its wrapped type would > be legal. Therefore, `int` is valid when the bound is `T extends Number`, > but it would not be if the bound was, for example, `T extends InputStream`. > > ### §2.5 The *typearg_int* imaginary type. > > Anytime a primitive type is encountered as a type argument, the compiler > needs to keep track of the notion that the primitive type is used as type > bound. For example, the compiler will usually have to inject synthetic > methods that replace the primitive type with its wrapper type. To help > clarify the actions that the compiler needs to take, we'll call any `int` > that appears in a location where it is being used to fit a type variable as > the imaginary `typearg_int` type. This isn't a real type, just a virtual > construct of the compiler. This concept already exists in java. If, for > example, you write the following code: > > ? ?public abstract class Example implements List { > ? ? ? ?@Override public boolean void add(String x) { > ? ? ? ? ? ?return true; > ? ? ? ?} > ? ?} > > and inspect the class produced by javac, you'll notice 2, and not 1, `add` > method; you'll see `add(Object)` as well as `add(String)` in the generated > class file. The `add(Object)` simply passes the call to the `add(String x)` > method, which involves a type cast. For primitive types, this concept is no > different: > > ? ?public abstract class Example implements List { > ? ? ? ?@Override public boolean void add(int x) { > ? ? ? ? ? ?return true; > ? ? ? ?} > ? ?} > > would result in not just `add(int)` but also `add(Object)` which simply > passes the call on. In addition to a type cast (to `java.lang.Integer`), > this wrapper method will also auto-unbox the object. > > ### Sugar > > #### §2.6 Field Read > > Anytime a field of type "int" is read, the compiler emits bytecode: > > ? ?GETFIELD/GETSTATIC "java/awt/Point" "x" "I" > > However, if a field of type "typearg_int" is read, it is unboxed first, so, > the compiler emits: > > ? ?GETFIELD/GETSTATIC "java/awt/Point" "x" "Ljava/lang/Object;" > ? ?INVOKEVIRTUAL "java/lang/Integer" "intValue" "()I" > > In other words, the field is assumed to be of the erased typevar's type > (Object in the example, but could also be e.g. `Number`), is assumed to > contain an `Integer` object, and `intValue()` is called on it. > > This act may result in the usual `ClassCastException` if heap pollution has > occurred, but can additionally also result in a `NullPointerException`, even > without heap pollution. This is analogous to auto-unboxing causing an NPE, > which is in the current Java6 also possible even if heap pollution has not > taken place. The java community has embraced autoboxing/unboxing even with > this shortcoming in the typing system, hence this similar case, which is not > readily solvable, can be considered the same way: A problem, but not a > show-stopper. > > #### §2.7 Field Write > > Analogous to field read; instead of generating a `PUTFIELD` of type "I", the > erased typevar's type is used instead, and a call to `INVOKESTATIC > "java/lang/Integer" "valueOf" "(I)Ljava/lang/Integer;"` is inserted before > the `PUTFIELD` instruction. > > Unlike the field read, there's no NullPointerException issue here. > > #### §2.8 Creating a field with a "typearg_int" type. > > This isn't possible; Fields cannot be overridden, they can only be shadowed. > Fields *can* of course be defined as having a type variable as type, but a > type variable's actual type is unknown. For example: > > ? ?public class Foo { > ? ? ? ?T x; > ? ?} > > The `T` can be anything and is in practice erased to `java.lang.Object`. > This erasure will not change because of this proposal, and an erasure to a > primitive type isn't possible, because `` is not legal. > > #### §2.9 Method invocation > > When invoking a method where one or more parameters is of type > `typearg_int`, then during the creation of the bytecode to load the > parameters on the stack, an `INVOKESTATIC` to `Integer.valueOf(int)` is > generated to box the primitive. Similarly, the signature generated in the > `INVOKEVIRTUAL`/`INVOKESTATIC` call is of the erased typevar's type and not > `I`. > > If the invoked method's return type is of type `typearg_int`, the return > type in the signature is as usual replaced with the erased typevar's type. > Unless the return value is discarded because the method invocation appears > as expression statement, an `INVOKEVIRTUAL` call to `Integer.intValue()` is > inserted immediately after the `INVOKEVIRTUAL`/`INVOKESTATIC` instruction. > > #### §2.10 Method declaration (Preamble) > > This part of the spec gets somewhat complicated, but this complication is > not new! For example, imagine the following two types: > > ? ?public class A { > ? ? ? ?void foo(T in) {} > ? ?} > > ? ?public class B extends A { > ? ? ? ?void foo(String in) {} > ? ?} > > The current javac compiler solves this scenario by generating a synthetic > wrapper with the signature: `void foo(Object)`, as `A`'s `foo` method has > that erased type (`Object` is `T`'s type bound in class `A`). This synthetic > method wraps the call to `B`. You can actually see this in action by looking > at the stack trace you get when you throw an exception from `B.foo` and then > calling it via: `A x = new B(); x.foo("");` > > The current java gets even more complicated if the supertype contains both > `void foo(T)` and `void foo(String)`, which is of course legal as `T` erases > to `Object`, not `String`. When defining `void foo(String)` in `B`, *BOTH* > methods are overridden. Furthermore, trying to call `foo("")` on a variable > of type `A` is not possible; a *this call is ambiguous* error is > generated. This error cannot be avoided by casting the argument; only by > casting the receiver (an instance of `A`) to a raw type can `foo` even be > called in such a circumstance. > > The same problems occur when primitives are legal type bounds for type > variables, and the same solutions suffice as well. There is some friction > here, as the above java puzzler-esque exercise shows, but I'm not aware of > any proposal for e.g. Project Coin to adress this problem, and thus one can > safely conclude that this oddity is not that important. > > #### §2.11 Method Declaration (parameter) > > Let's say we have: > > ? ?public abstract class IntList implements List { > ? ? ? ?public boolean add(int v) {return false;} > ? } > > In this case, both the actual method is generated, as well as a synthetic > method where every `typearg_int` is replaced with `Ljava/lang/Object;` (the > erased type of typevar), i.e. both of these: > > ? ?add(I)Z > ? ?add(Ljava/lang/Object;)Z > > are generated, with the second method typecasting its argument to `Integer`, > unboxing it, and calling the first. Both `ClassCastException` and > `NullPointerException` can occur as part of this operation, but the former > only if heap pollution has taken place. > > Note there is no risk of an explosion of method signatures when a large > number of `typearg_int` typed parameters show up. In a hypothetical method > `add(T1 a, T2 b, T3 c)` with all 3 parameters a type variable, when all type > variables are bound to a primitive type, then only two methods are > generated: all 3 as primitive, and all 3 as wrapper type. Entirely analogous > to the convoluted example at the beginning of this section, if this method > is accessed as a `List`, the wrapper type version will be called, but > code that works directly with the `IntList` type will generate a call to the > primitive version. > > #### §2.12 Method Declaration (return type) > > Let's say we have: > > ? ?public abstract class IntList implements List { > ? ? ? ?public int get(int idx) {return 0;} > ? ?} > > In this case, again two versions are generated: > > ? ?get(I)I > ? ?get(I)Ljava/lang/Object; > > Where `Object` comes from the erased type of this particular version of > `typearg_int`. The second method simply calls on the first, boxes the > result, and returns that. > > If a method contains both `typearg_int` in its parameter list as well as its > return type, still only 2 methods are produced; one with all-primitives, and > one with all-wrappers. The wrapper will unbox parameters and box the > returned value. > > ### §2.13 The JRockit gambit > > It is virtually impossible to make something like this: > > ? ?List list = new ArrayList(); > > as efficient as an `int[]` without reification; `ArrayList`'s implementation > creates an `Object[]` to store the list's elements in, and once it does > this, the performance game is automatically lost - it must create an `int[]` > array to get performance that is comparable to the performance of a raw > `int` array. However, it couldn't possibly do this; when `ArrayList`'s > constructor is called, its type parameter has been erased, so `ArrayList` > simply cannot tell what kind of array it should make. However, all hope is > not lost here, as this can be made quite efficient: > > ? ? List list = new IntArrayList(); > > or, to avoid up to 8 new classes in java.util, these specialized classes can > be turned into inner classes of ArrayList, and ArrayList can gain a new > "static" constructor: > > ? ?List list = ArrayList.with(int.class); > > The above example is poor man's reification: This way ArrayList's "with" > static method can in fact create a new IntArrayList by runtime-inspecting > the `int.class` parameter. However, even with the receiver (`IntArrayList`) > being specifically built with the `int` primitive type in mind, and the > caller (the one that declared `List list`) also operating solely on the > primitives level, the above compilation strategy still means that the > following code: > > ? ?list.add(10); > > results in the following bytecode: > > ? ?ICONST 10 > ? ?INVOKESTATIC java/lang/Integer valueOf(I)Ljava/lang/Integer; > ? ?INVOKEVIRTUAL java/util/List add(Ljava/lang/Object;)Z > > ? ?.... execution moves to `IntArrayList`'s code > > ? ?INVOKEVIRTUAL java/lang/Integer intValue()I > ? ?INVOKEVIRTUAL java/util/IntArrayList add(I)Z > > ? ?.... > > The hotspot compiler will eventually inline the static call and the last 2 > calls (as they are to small final methods), but nevertheless there's an > object on the heap involved (the boxed integer), and two calls, even if > inlined. > > However, the JRockit VM already eliminates sequential box/unbox calls even > across invocations, which eliminates the heap object entirely. Together with > inlining the pass-through call from add(Object) to add(int) this call is > then just as fast as calling the *GNU Trove* `TIntArrayList`. See < > http://blogs.oracle.com/ohrstrom/2009/05/pulling_a_machine_code_rabbit.html> > for a treatise on how the JRockit VM handles eliminating sequential > box/unbox operations. > > In situations where either the receiver (such as `java.util.ArrayList`) or > the sender (some generic code that created a new list of it's own type > variable `E`) is not working exclusively with `int` this optimization > obviously won't work, _but_, this optimization would be impossible without > at least reification, which is not feasible for JDK7. > > ### §2.14 Generics Conversion > > A type such as `Map` can be treated as a `Map extends Object>` implicitly. The same property is granted to primitives; a > primitive will readily convert to its wrapper type, which includes > conversion to a (bound) wildcard as `Integer` has a place in the type > hierarchy. In other words, a `Map` will implicitly convert to > a `Map`, for example. This leads automatically to a > dilemma; it means `List` can be treated as a `List`, and in > that way, `null` can be added to this list which isn't technically > compatible with primitives, and as a result, treating this list as a > `List` again can result in a `NullPointerException`. This type > conversion feels like autoboxing/unboxing which suffers from the same > problem, and as covered this omission in the type system has been deemed > acceptable before. As has been stated, `int` as a type bound is legal > anywhere `Integer` would be, which implies that converting from for example > `List` to `List` is also legal. > > ### §2.15 The benefit to the java community - recap > > Even without the JRockit optimization (which can at any time be added > without requiring changes to this spec, which is focussed on the JLS and the > compiler, and not the VM), this proposal is highly beneficial to the java > community. Generified libraries virtually never offer primitive-optimized > versions. For example, there is no ArrayList-like class for primitive ints > in the java runtime; one would have to reach for third party libraries such > as GNU Trove to find them. The large amount of code duplication that is > required to produce a primitive-optimized version for all 8 primitive types > is also very inpractical. It is clear, then, that the java community has > decided to accept the performance penalty, and more problematically, the > readability penalty, by choosing to use for example `List`. The > readily available alternative, arrays, are continuously problematic in new > proposals, as they don't work well together with generics and have different > variance rules. > > This proposal would also help greatly in APIs which are designed with > primitive arrays in mind. For example, the java.util.Arrays class has a > utility method to sort an int[], but only by the natural order of integers. > There is no `Comparator` based method for `int[]` in `java.util.Arrays`; > there is only such a method for sorting `T[]`, and `T` can currently only > stand for non-primitive types. With this feature, the following code could > be legal: > > ? ?int[] array = {1, -3, 2, 8, 6}; > ? ?Arrays.sort(array, new Comparator { > ? ? ? ?public int compare(int a, int b) { > ? ? ? ? ? ?a = Math.abs(a); b = Math.abs(b); > ? ? ? ? ? ?return a < b ? -1 : a > b ? 1 : 0; > ? ? ? ?} > ? ?}); > > or, with closure support: > > ? ?Arrays.sort(array, #(int a, int b) { > ? ? ? ?a = Math.abs(a); b = Math.abs(b); > ? ? ? ?return a < b ? -1 : a > b ? 1 : 0; > ? ?}); > > In other words, convenient syntax, fast execution, while *keeping* the > `Comparator` concept. Comparator cannot obviously be removed (it would not > be backwards compatible), and it would be inconsistent for the sorting APIs > to work with `Comparator` when sorting Objects, but to work with `#int(int, > int)` closures when trying to sort an array of primitive ints. > > ### §3 Curses! What about arrays! > > There's one case that this proposal has not yet covered: What happens when > `typearg_int` is used in an array? > > Let's say we have: > > ? ?public class Foo { > ? ? ? ?protected T[] array = null; > ? ? ? ?public abstract void method(T[] param); > ? ? ? ?public abstract T[] returnType(); > ? } > > What would happen if we tried to write: > > ? ?public class Bar extends Foo { > ? ? ? ?@Override public void method(int[] param) { > ? ? ? ? ? ?this.array = param; > ? ? ? ?} > > ? ? ? ?@Override public int[] returnType() { > ? ? ? ? ? ?return param; > ? ? ? ?} > ? ?} > > This question seems academic, in that generics and arrays almost never meet, > but that isn't quite true: `java.util.Collection` itself contains `public > abstract T[] toList(T[] in);`. It is important to realize that because > arrays and generics are already convoluted when used together in java6, the > `T` in that signature is not related to the `E` of List itself (the `E` in > `public interface Collection`!). For usage in method declarations the > wrapper methods can create a new array and copy each element, > autoboxing/unboxing on the way. This is mind-bogglingly inefficient, but it > is simple. In practice the authors strongly suggest the implementer of > `IntArrayList` write a specific method to get a straight `int[]` array > without this convolution which obviously cannot be optimized by the VM the > way a single `int` to/from `Integer` conversion can be. For array access, > the proposal suggests treating this concept as extremely rare and thus > coming up with the simplest thing that could possibly work: Access to the > array (read/write) is allowed and involves boxing as usual, but a reference > to `Foo.array` itself will simply remain its erased type and emits a > warning. Therefore: > > ? ?public abstract class Bar extends Foo { > ? ? ? ?void test() { > ? ? ? ? ? ?Object[] o = array; //warning but legal > ? ? ? ? ? ?int[] p = array; ? ?//error > ? ? ? ?} > ? ?} > > Nevertheless this concept introduces an API incompatibility: The javadoc for > `toList` states that if the input array has enough room, the same array will > be returned, and this cannot of course be done if the input array is first > number-for-number copied into a `Object[]` array, and then after the copy > operation has completed, this array is translated back to `int[]`. This > proposal offers no solution to this dilemma. It can only note that as `int` > is currently illegal in generics, it is technically backwards compatible to > add a note to the javadoc that explains the same array is *not* returned > even if it has enough room if the type bound is a primitive. > > It also shows a gap in the API of a hypothetical `IntArrayList`: The > signature (as mandated by the `Collection` interface) must be `public > T[] toArray(T[] in)`, and as `T[]`'s erasure, which is `Object[]`, is not > compatible with `int[]`, this method cannot be made fast even for a specific > subtype such as `IntArrayList`. This proposal offers no pragmatic solution > other than to create a custom method in `IntArrayList` as well as a static > utility method in `java.util.Collections` that can translate any list to > `int[]`, which uses an instanceof check to pick up > `java.util.ArrayList.IntArrayList`s special method and use that. > > The second issue raised is, in `public T[] toArray(T[] in)`, what > happens if the calling code ends up binding `int` to `T`? This is a > particularly painful process: Javac needs to generate the conversion from > `int[]` to `Integer[]` prior to calling the method, and then the method will > most likely convert back to `int[]`, and on the return phase the same double > convert occurs for a grand total of 4 conversions. To avoid accidental > triggering of this potentially very slow operation, a warning should be > emitted anytime the compiler generates conversion code to convert a > primitive array to a non-primitive array in order to fit with the erased > signature of an invoked method. (For fields, as mentioned, the arrays remain > their erased type, and an attempt to treat them as primitive array results > in an error). > > From neal at gafter.com Tue Mar 9 16:59:12 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 9 Mar 2010 16:59:12 -0800 Subject: call operator and orthogonality with existing VM internals In-Reply-To: <4B96D841.9080805@hapra.at> References: <4B95325D.3020702@hapra.at> <4B9532F5.9030702@hapra.at> <15e8b9d21003080958j65a0551cqc51ea2cdf45e559b@mail.gmail.com> <4B963DCC.5050100@hapra.at> <15e8b9d21003090847k763d37cagb64da868d13c7c54@mail.gmail.com> <4B968458.2010702@hapra.at> <15e8b9d21003090957v69a5b4c5n644ec8d2ebdddad8@mail.gmail.com> <4B96D841.9080805@hapra.at> Message-ID: <15e8b9d21003091659l285c0808x1ef3460d21797b38@mail.gmail.com> Jakob- What you're describing is called declaration-site variance (as opposed to wildcards, which are use-site variance). It has been brought up before both for project coin and project lambda, and in both cases was declared outside of the scope of the projects. Cheers, Neal On Tue, Mar 9, 2010 at 3:22 PM, Jakob Praher wrote: > Neal Gafter wrote: >> On Tue, Mar 9, 2010 at 9:24 AM, Jakob Praher wrote: >> >> Which is why BGGA provides a special syntax for function types that >> inserts the wildcards for you. >> >> > When talking about Java on the whole (not the feature of adding function > types), it might make sense to add support for covariant/contravariant > annotations on types? Maybe it is enough to be able to use wildcards > inside interface defintions: > > For instance > ? interface Function1 { ... } > would just mean that every usage of Function1 is replaced by > Function1. The wildcards are stored in the type > itself. It might not make sense to you to use exactly wildcards in the > type definition this way, but I did not want to introduce a new syntax. > > This checks are done by the compiler (due to type erasure). There might > be a better way to express this yet other than that the implementation > could be done. Given that throws had to be added if the BGGA route would > be taken (no?), was there any compelling reason not to consider variance > qulifiers in type declarations? IMHO the big plus is that interface > types are concise again. And the feature could be used in general. I > also see no difference if every type of a function is automatically > translated to have wildcards. > > And if I may add wildcards arbitrarily in type declarations I do not > think it is dangerous to declare them generically in the type definition. > > Scala takes a similar route and allows variance annotations on generic > types. There are some additional checks such that the type declaring the > annotations must conform to covariance and contravariance. See chapter 4 > section 5 of the Scala Language Specification [1]. > > -- Jakob > > [1] - > http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf > From reinier at zwitserloot.com Wed Mar 10 05:05:12 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 10 Mar 2010 14:05:12 +0100 Subject: Primitives in Generics proposal. In-Reply-To: <15e8b9d21003091657x1d715adfo5464518eea8a3070@mail.gmail.com> References: <560fb5ed1003091328k7cde27fcn9c14d9f1881b30b2@mail.gmail.com> <15e8b9d21003091657x1d715adfo5464518eea8a3070@mail.gmail.com> Message-ID: <560fb5ed1003100505k23bffe5dlb9f34742cae25a3@mail.gmail.com> I'll rebut point by point; 1: int[] <-> Integer[] conversion doesn't preserve reference identity. This rule has been broken before. In java 1.5, this assert isn't true, because reference identity isn't maintained when boxing is applied: Integer x = new Integer(10000000); int y = x; Integer z = x; assert z == x; //This will fail! The Java Language Spec has been updated to explain that autoboxing operations are simply syntax sugar for inserting either Integer.valueOf(i) or i.intValue(), and this case is no different: When T[] is being supplied by or assigned to an array where T is bound to an integer, a conversion takes place that does not adhere to reference identity, is slow, and emits a warning precisely to highlight conversion is happening. If this issue cannot be suitably solved, consider instead an amended proposal where any such conversion is simply not allowed. There's virtually zero usage of arrays and generics precisely because they already don't work very well together. This solution to generics and arrays not working together very well is to reduce the need for arrays in the first place, which this proposal does. The most common usage of generics and arrays, Collection's toArray(T[]) method, is already awkward and bordering on broken; You must supply a T array, and the T type is not related to the E type, yet if they don't match appropriately you'll get ArrayStoreExceptions or ClassCastExceptions. Regardless, the toArray() method never supported primitive arrays before, so no current code is going to break. 2. This proposal would need (partial) reification. No it doesn't; point out where in the proposal anything in the JVM needs to change. Any usage of a primitive types as binding for a type argument is treated as "Integer" in the generated class file. It's all sugar, the VM doesn't have to change at all. The proposal does strongly recommend optimizing sequential box/unbox operations, but it isn't necessary to go forward, and can safely be added at a later date, such when the JRockit and sun VMs are integrated. 3. Type arguments themselves can be used as type bound. Yes, they can. However, If we have "T extends C", then C cannot be bound to just "int" - from javac's perspective the bound will "typearg_int". Hence javac knows that T then becomes "typearg_int" as well. "typearg_int" acts like Integer on the output (class file generation side), and as "int" on the input (code resolution side), except where the proposal lists special rules for handling with them (which occur on the intersections: field read/write, method invocation, overriding method declarations, etc). 4. Subtyping relationship amongst the primitives. It's technically true but this is a second-class citizen and not at all the same as the subtyping relation between non-primitive types. Here's one example of a method that just doesn't care about them: sysout(byte.class.isAssignableFrom(int.class)); sysout(int.class.isAssignableFrom(byte.class)); both of these print "false". A technical analysis of isAssignableFrom's javadoc shows that isAssignableFrom's implementation isn't buggy, but it doesn't even mention this explicitly, it instead uses a large amount of JLS jargon that only a JLS expert could decode to conclude that its omission of the subtyping rules amongst primitive types is not an implementation error. Nevertheless I've never seen this omission come up as a practical problem. I'm having a very hard time coming up with code that presumes the Primitives in Generics proposal is implemented that is confusing or surprising in a way that doesn't cause an immediate compiler error/warning that explains exactly what just happened. For example, the following will just work and preserves the subtyping relationship amongst the primitives: List list = new ArrayList(); list.add(10); The reason it works: During method resolution of the add call, the compiler finds only one add method, namely add, which, after filling in the bound, becomes add. typearg_long is like Long on the output (JVM) side, but it's like long on the input (java code) side. This is no different here, so the compiler ends up with list.add(long) as the target method. There's an int there, which will be converted to a long via a widening primitive conversion. This is no different then any other method that takes a long (even if it doesn't involve generics) and is given an int; the JVM doesn't accept this but javac does and generates conversion bytecode to facilitate the invocation. So, can you show me some code that is ambiguous / confusing / surprising when analysed with the proposal, that isn't trivially solvable like the above case? 5. There's no time / this is out of scope. As the posts from amongst others Stephen Colebourne, which suggest looking at abolishing function type references altogether, as well as the recent flurry of issues raised about having function type references in the first place (such as having an array of function types being essentially impossible) indicate, evolving generics to handle the niches that function types have been invented for (whittling down ParallelArray's 132 Ops SAM types into a manageable set) is entirely in scope. As far as time is concerned, if this proposal means that function types can be abolished, all the time saved by not having to implement them goes a very long way towards finishing analysis and implementation of this proposal instead. Even if this proposal is slightly more complicated to implement than the handicapped function types proposal where Project Lambda seems to be heading, it's clearly worth it, as primitives in generics is a great feature by itself. Do you have an answer for the dilemma of ParallelArray's Comparator issue? Using java.util.Comparator only for object-based PA's is inconsistent, but adding IntComparator types is exactly the kind of thing the closure proposal tries to fight (in that one of its stated aims is finding a way around Ops's 132 SAM types). It would be a grave mistake to implement a java feature now in an inferior way that's going to cause backwards compatibility ugliness forever when we knew of a better solution but didn't implement it due to a lack of time. --Reinier Zwitserloot On Wed, Mar 10, 2010 at 1:57 AM, Neal Gafter wrote: > Reinier- > > An interesting idea, but unfortunately it is far larger in scope than > project lambda, and requires a much deeper and more formal design of > the type system impact. A type parameter implicitly "extends Object", > but primitives do not. > > There are a few fatal flaws in your suggested approaches. First, > subtype operations need to preserve reference identity, for reasons > discussed earlier. Your plan to convert int[] to Integer[] and back > again undermines that. Second, the boxing conversions blur but do not > erase the distinction between primitives and reference types. You are > simply incorrect when you say that primitives do not have subtypes. > byte is a subtype of long but Byte is not a subtype of Long. Third, > you cannot forbid primitives as bounds, even if primitives are > considered invariant for the purposes of generics, because type > parameters can be used as bounds too. Arrays of primitives are not > syntactically allowed as bounds, but that is a syntactic restriction > only, as type parameters can be primitive-array types, and type > parameters can be bounds. > > It is hard to see how this can be implemented without at least > partially reifying generics, as the bytecode to handle primitives > differs from the code to handle reference types. Java has separate > compilation and runtime binding, exposed in the language as "binary > compatibility"; to support that, the VM must generate specializations > at runtime. > > Cheers, > Neal > > On Tue, Mar 9, 2010 at 1:28 PM, Reinier Zwitserloot > wrote: > > As Stephen Colebourne already suggested, the various problems with > function > > types can be sidestepped rather simply by sticking purely with (SAM) type > > names, immediately fitting any lambda to an appropriate SAM type. > However, > > to feasibly go this route, generics _need_ to be able to work with > primitive > > types, in order to reduce ParallelArray's 132 SAM types in Ops down to a > > nice lean 8. > > > > I've written up a proposal to get the discussion going. If indeed the > > existence of such a proposal results in a much simpler Project Lambda, > then > > the time saved implementing Project Lambda can be used to implement this > > idea. It should go without saying that allowing primitives in generics > would > > be a great feature for JDK7 on its own. > > > > The canonical version that will be updated and is nice on the eyes can be > > found here: > > > > http://projectlombok.org/primitive_generics/ > > > > > > but in the interests of saving all discussion in one thread I've pasted > the > > markdown source of v1.0 below. > > > > Happy reading! > > > > > > # Primitives in generics proposal > > > > v1.0 > > > > by Reinier Zwitserloot > > > > > > ## §1 Preamble and necessity of the feature > > > > The goal of this proposal is to allow primitives in generics. To simplify > > the proposal, `int` is used in all examples and in all text. All the > other 7 > > primitive types are of course also allowed as type arguments. In > particular, > > a closure strategy for JDK7's [Project Lambda][] to always _box_ any > closure > > into a so-called SAM type is a far more realistic option if the used SAM > > types can accept primitives in their generics. (a type that contains > > exactly 1 abstract method, usually an interface. For example, > > `java.util.Comparator` is a SAM type. So is `java.lang.Runnable`). For > > example, [jsr166y-extra - Parallel Arrays][jsr166yx], the standard > usecase > > example for Project Lambda, currently lists 132 SAM interface types in > its > > [Ops]( > > http://gee.cs.oswego.edu/dl/jsr166/dist/extra166ydocs/extra166y/Ops.html > ) > > container class, but most of those are simply to provide a > primitive-based > > version of a few central concepts. If primitive generics were possible, > this > > list of 132 would be reduced to a much more manageable set. To be > precise: > > > > Ops.Op > > Ops.BinaryOp > > Ops.Predicate > > Ops.BinaryPredicate > > Ops.Procedure > > Ops.Generator > > Ops.Reducer extends BinaryOp > > java.util.Comparator > > Ops.Action > > > > These names are more meaningful than their equivalent purely structural > > function type constructs. For example, jsr166yx includes the concept of a > > `Ops.Reducer` even though the signature of a reducer is 100% equivalent > to > > the more general `Op` class. It is self-evident then that the designers > of > > jsr166yx find this kind of purely name-based distinction important enough > to > > dedicate 4 of Ops' 132 SAM types to it even though they didn't have to. > > > > Furthermore, as the inclusion of `java.util.Comparator` foreshadowed, > > sticking with names for function types fits better with existing java > code. > > jsr166yx as it stands uses `java.util`'s version of Comparator for its > > Object based `ParallelArray` but defined its own versions for the > > primitives, such as `Ops.LongComparator`. If function types were > introduced > > instead, then jsr166yx would obviously replace its `Ops.LongComparator` > with > > `#int(long, long)` but it would face a dilemma for its `Object` based > > `ParallelArray`: Should it take `#int(T, T)`, should it take > > `java.util.Comparator`, or should it take both? None of these three > > options are fully consistent. This isn't a rare coincidence; the amount > of > > SAM types that are in active use across the java community is staggering, > > and introducing function types to solve the primitives problem is going > to > > introduce a lot of inconsistency as APIs evolve to accept closures but > keep > > their old SAM based methods for backwards compatibility. > > > > The solution is as clear as it is obvious: Make primitives allowable as > type > > argument. Together with a relatively minor and proven (by JRockit which > > already includes it) JVM optimization, both the API and the performance > > issues can be solved. > > > > As a secondary step, one could start questioning if, once this feature > has > > been added, function types are even necessary. As recent traffic on the > > [Project Lambda mailing list]( > > http://mail.openjdk.java.net/mailman/listinfo/lambda-dev) has indicated, > > there are a host of issues with function types, from syntax ambiguities > to > > problems around allowing arrays of function types. By sticking with SAM > > types, no new ideas are introduced for the java community to learn; they > > presumably already know that for example the expression `new > > Comparator[10]` is not legal. > > > > Last but certainly not least: Primitives as type arguments are a great > > feature for the java language all by themselves and not only as a part of > a > > closure proposal. For example, if this proposal is implemented in JDK7, > the > > following could be allowed: `List intList = new IntList();` and be > > virtually as fast as a purely `int` array based list implementation such > as > > the ones that can be found in [GNU Trove]( > > http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntArrayList.html), > but > > which is API compatible with `java.util.List`. > > > > This v1.0 of the proposal does not highlight which sections of the JLS > are > > involved or need to be changed. Its primary intention is to start a > > discussion, explore the feasibility, if it has clear solutions for all > > potential issues, and if it can lead to a simplification of Project > Lambda, > > thus freeing up enough time in the JDK7 schedule to implement it. > > > > > > [Project Lambda]: http://openjdk.java.net/projects/lambda/ "Project > Lambda > > Mailing List" > > [jsr166yx]: http://gee.cs.oswego.edu/dl/concurrency-interest/ "jsr166y - > > Parallel Arrays" > > > > ## §2 Proposal > > > > ### §2.1 Type Variables > > > > Type variables are the `T` in `public class Foo {}`. Type variables > can > > only include actual types in their bounds, such as ``. > As > > `T extends int` doesn't really convey a useful construct, we simply won't > > allow it. This means type variables themselves don't have to change at > all. > > > > ### §2.2 Type Arguments > > > > Type Arguments come in two flavours: Just the type, as in: > `List`, > > or as a bound, such as `List`. As primitive types don't > > really have subtype relations, there is again not much sense in allowing > > either `List` or `List`. It is therefore not > > allowed; *only* `List` would be legal. To be precise, `List extends > > Set>` would be allowed, but `List>` would not be. > > > > ### §2.3 Syntax Sugar > > > > The JVM barely supports generics (instances don't preserve their type > > arguments, and method signatures don't either), and changing the JVM is a > > major undertaking so this proposal does not include any required changes > to > > the JVM. Therefore, Something like `List x;` is effectively syntax > > sugar similar to how `List x;` is effectively syntax sugar. > > > > ### §2.4 Legality of primitive type arguments. > > > > A primitive can be bound to a type argument anywhere its wrapped type > would > > be legal. Therefore, `int` is valid when the bound is `T extends Number`, > > but it would not be if the bound was, for example, `T extends > InputStream`. > > > > ### §2.5 The *typearg_int* imaginary type. > > > > Anytime a primitive type is encountered as a type argument, the compiler > > needs to keep track of the notion that the primitive type is used as type > > bound. For example, the compiler will usually have to inject synthetic > > methods that replace the primitive type with its wrapper type. To help > > clarify the actions that the compiler needs to take, we'll call any `int` > > that appears in a location where it is being used to fit a type variable > as > > the imaginary `typearg_int` type. This isn't a real type, just a virtual > > construct of the compiler. This concept already exists in java. If, for > > example, you write the following code: > > > > public abstract class Example implements List { > > @Override public boolean void add(String x) { > > return true; > > } > > } > > > > and inspect the class produced by javac, you'll notice 2, and not 1, > `add` > > method; you'll see `add(Object)` as well as `add(String)` in the > generated > > class file. The `add(Object)` simply passes the call to the `add(String > x)` > > method, which involves a type cast. For primitive types, this concept is > no > > different: > > > > public abstract class Example implements List { > > @Override public boolean void add(int x) { > > return true; > > } > > } > > > > would result in not just `add(int)` but also `add(Object)` which simply > > passes the call on. In addition to a type cast (to `java.lang.Integer`), > > this wrapper method will also auto-unbox the object. > > > > ### Sugar > > > > #### §2.6 Field Read > > > > Anytime a field of type "int" is read, the compiler emits bytecode: > > > > GETFIELD/GETSTATIC "java/awt/Point" "x" "I" > > > > However, if a field of type "typearg_int" is read, it is unboxed first, > so, > > the compiler emits: > > > > GETFIELD/GETSTATIC "java/awt/Point" "x" "Ljava/lang/Object;" > > INVOKEVIRTUAL "java/lang/Integer" "intValue" "()I" > > > > In other words, the field is assumed to be of the erased typevar's type > > (Object in the example, but could also be e.g. `Number`), is assumed to > > contain an `Integer` object, and `intValue()` is called on it. > > > > This act may result in the usual `ClassCastException` if heap pollution > has > > occurred, but can additionally also result in a `NullPointerException`, > even > > without heap pollution. This is analogous to auto-unboxing causing an > NPE, > > which is in the current Java6 also possible even if heap pollution has > not > > taken place. The java community has embraced autoboxing/unboxing even > with > > this shortcoming in the typing system, hence this similar case, which is > not > > readily solvable, can be considered the same way: A problem, but not a > > show-stopper. > > > > #### §2.7 Field Write > > > > Analogous to field read; instead of generating a `PUTFIELD` of type "I", > the > > erased typevar's type is used instead, and a call to `INVOKESTATIC > > "java/lang/Integer" "valueOf" "(I)Ljava/lang/Integer;"` is inserted > before > > the `PUTFIELD` instruction. > > > > Unlike the field read, there's no NullPointerException issue here. > > > > #### §2.8 Creating a field with a "typearg_int" type. > > > > This isn't possible; Fields cannot be overridden, they can only be > shadowed. > > Fields *can* of course be defined as having a type variable as type, but > a > > type variable's actual type is unknown. For example: > > > > public class Foo { > > T x; > > } > > > > The `T` can be anything and is in practice erased to `java.lang.Object`. > > This erasure will not change because of this proposal, and an erasure to > a > > primitive type isn't possible, because `` is not legal. > > > > #### §2.9 Method invocation > > > > When invoking a method where one or more parameters is of type > > `typearg_int`, then during the creation of the bytecode to load the > > parameters on the stack, an `INVOKESTATIC` to `Integer.valueOf(int)` is > > generated to box the primitive. Similarly, the signature generated in the > > `INVOKEVIRTUAL`/`INVOKESTATIC` call is of the erased typevar's type and > not > > `I`. > > > > If the invoked method's return type is of type `typearg_int`, the return > > type in the signature is as usual replaced with the erased typevar's > type. > > Unless the return value is discarded because the method invocation > appears > > as expression statement, an `INVOKEVIRTUAL` call to `Integer.intValue()` > is > > inserted immediately after the `INVOKEVIRTUAL`/`INVOKESTATIC` > instruction. > > > > #### §2.10 Method declaration (Preamble) > > > > This part of the spec gets somewhat complicated, but this complication is > > not new! For example, imagine the following two types: > > > > public class A { > > void foo(T in) {} > > } > > > > public class B extends A { > > void foo(String in) {} > > } > > > > The current javac compiler solves this scenario by generating a synthetic > > wrapper with the signature: `void foo(Object)`, as `A`'s `foo` method has > > that erased type (`Object` is `T`'s type bound in class `A`). This > synthetic > > method wraps the call to `B`. You can actually see this in action by > looking > > at the stack trace you get when you throw an exception from `B.foo` and > then > > calling it via: `A x = new B(); x.foo("");` > > > > The current java gets even more complicated if the supertype contains > both > > `void foo(T)` and `void foo(String)`, which is of course legal as `T` > erases > > to `Object`, not `String`. When defining `void foo(String)` in `B`, > *BOTH* > > methods are overridden. Furthermore, trying to call `foo("")` on a > variable > > of type `A` is not possible; a *this call is ambiguous* error is > > generated. This error cannot be avoided by casting the argument; only by > > casting the receiver (an instance of `A`) to a raw type can `foo` even be > > called in such a circumstance. > > > > The same problems occur when primitives are legal type bounds for type > > variables, and the same solutions suffice as well. There is some friction > > here, as the above java puzzler-esque exercise shows, but I'm not aware > of > > any proposal for e.g. Project Coin to adress this problem, and thus one > can > > safely conclude that this oddity is not that important. > > > > #### §2.11 Method Declaration (parameter) > > > > Let's say we have: > > > > public abstract class IntList implements List { > > public boolean add(int v) {return false;} > > } > > > > In this case, both the actual method is generated, as well as a synthetic > > method where every `typearg_int` is replaced with `Ljava/lang/Object;` > (the > > erased type of typevar), i.e. both of these: > > > > add(I)Z > > add(Ljava/lang/Object;)Z > > > > are generated, with the second method typecasting its argument to > `Integer`, > > unboxing it, and calling the first. Both `ClassCastException` and > > `NullPointerException` can occur as part of this operation, but the > former > > only if heap pollution has taken place. > > > > Note there is no risk of an explosion of method signatures when a large > > number of `typearg_int` typed parameters show up. In a hypothetical > method > > `add(T1 a, T2 b, T3 c)` with all 3 parameters a type variable, when all > type > > variables are bound to a primitive type, then only two methods are > > generated: all 3 as primitive, and all 3 as wrapper type. Entirely > analogous > > to the convoluted example at the beginning of this section, if this > method > > is accessed as a `List`, the wrapper type version will be called, > but > > code that works directly with the `IntList` type will generate a call to > the > > primitive version. > > > > #### §2.12 Method Declaration (return type) > > > > Let's say we have: > > > > public abstract class IntList implements List { > > public int get(int idx) {return 0;} > > } > > > > In this case, again two versions are generated: > > > > get(I)I > > get(I)Ljava/lang/Object; > > > > Where `Object` comes from the erased type of this particular version of > > `typearg_int`. The second method simply calls on the first, boxes the > > result, and returns that. > > > > If a method contains both `typearg_int` in its parameter list as well as > its > > return type, still only 2 methods are produced; one with all-primitives, > and > > one with all-wrappers. The wrapper will unbox parameters and box the > > returned value. > > > > ### §2.13 The JRockit gambit > > > > It is virtually impossible to make something like this: > > > > List list = new ArrayList(); > > > > as efficient as an `int[]` without reification; `ArrayList`'s > implementation > > creates an `Object[]` to store the list's elements in, and once it does > > this, the performance game is automatically lost - it must create an > `int[]` > > array to get performance that is comparable to the performance of a raw > > `int` array. However, it couldn't possibly do this; when `ArrayList`'s > > constructor is called, its type parameter has been erased, so `ArrayList` > > simply cannot tell what kind of array it should make. However, all hope > is > > not lost here, as this can be made quite efficient: > > > > List list = new IntArrayList(); > > > > or, to avoid up to 8 new classes in java.util, these specialized classes > can > > be turned into inner classes of ArrayList, and ArrayList can gain a new > > "static" constructor: > > > > List list = ArrayList.with(int.class); > > > > The above example is poor man's reification: This way ArrayList's "with" > > static method can in fact create a new IntArrayList by runtime-inspecting > > the `int.class` parameter. However, even with the receiver > (`IntArrayList`) > > being specifically built with the `int` primitive type in mind, and the > > caller (the one that declared `List list`) also operating solely on > the > > primitives level, the above compilation strategy still means that the > > following code: > > > > list.add(10); > > > > results in the following bytecode: > > > > ICONST 10 > > INVOKESTATIC java/lang/Integer valueOf(I)Ljava/lang/Integer; > > INVOKEVIRTUAL java/util/List add(Ljava/lang/Object;)Z > > > > .... execution moves to `IntArrayList`'s code > > > > INVOKEVIRTUAL java/lang/Integer intValue()I > > INVOKEVIRTUAL java/util/IntArrayList add(I)Z > > > > .... > > > > The hotspot compiler will eventually inline the static call and the last > 2 > > calls (as they are to small final methods), but nevertheless there's an > > object on the heap involved (the boxed integer), and two calls, even if > > inlined. > > > > However, the JRockit VM already eliminates sequential box/unbox calls > even > > across invocations, which eliminates the heap object entirely. Together > with > > inlining the pass-through call from add(Object) to add(int) this call is > > then just as fast as calling the *GNU Trove* `TIntArrayList`. See < > > > http://blogs.oracle.com/ohrstrom/2009/05/pulling_a_machine_code_rabbit.html > > > > for a treatise on how the JRockit VM handles eliminating sequential > > box/unbox operations. > > > > In situations where either the receiver (such as `java.util.ArrayList`) > or > > the sender (some generic code that created a new list of it's own type > > variable `E`) is not working exclusively with `int` this optimization > > obviously won't work, _but_, this optimization would be impossible > without > > at least reification, which is not feasible for JDK7. > > > > ### §2.14 Generics Conversion > > > > A type such as `Map` can be treated as a `Map > extends Object>` implicitly. The same property is granted to primitives; > a > > primitive will readily convert to its wrapper type, which includes > > conversion to a (bound) wildcard as `Integer` has a place in the type > > hierarchy. In other words, a `Map` will implicitly convert > to > > a `Map`, for example. This leads automatically to a > > dilemma; it means `List` can be treated as a `List`, and in > > that way, `null` can be added to this list which isn't technically > > compatible with primitives, and as a result, treating this list as a > > `List` again can result in a `NullPointerException`. This type > > conversion feels like autoboxing/unboxing which suffers from the same > > problem, and as covered this omission in the type system has been deemed > > acceptable before. As has been stated, `int` as a type bound is legal > > anywhere `Integer` would be, which implies that converting from for > example > > `List` to `List` is also legal. > > > > ### §2.15 The benefit to the java community - recap > > > > Even without the JRockit optimization (which can at any time be added > > without requiring changes to this spec, which is focussed on the JLS and > the > > compiler, and not the VM), this proposal is highly beneficial to the java > > community. Generified libraries virtually never offer primitive-optimized > > versions. For example, there is no ArrayList-like class for primitive > ints > > in the java runtime; one would have to reach for third party libraries > such > > as GNU Trove to find them. The large amount of code duplication that is > > required to produce a primitive-optimized version for all 8 primitive > types > > is also very inpractical. It is clear, then, that the java community has > > decided to accept the performance penalty, and more problematically, the > > readability penalty, by choosing to use for example `List`. The > > readily available alternative, arrays, are continuously problematic in > new > > proposals, as they don't work well together with generics and have > different > > variance rules. > > > > This proposal would also help greatly in APIs which are designed with > > primitive arrays in mind. For example, the java.util.Arrays class has a > > utility method to sort an int[], but only by the natural order of > integers. > > There is no `Comparator` based method for `int[]` in `java.util.Arrays`; > > there is only such a method for sorting `T[]`, and `T` can currently only > > stand for non-primitive types. With this feature, the following code > could > > be legal: > > > > int[] array = {1, -3, 2, 8, 6}; > > Arrays.sort(array, new Comparator { > > public int compare(int a, int b) { > > a = Math.abs(a); b = Math.abs(b); > > return a < b ? -1 : a > b ? 1 : 0; > > } > > }); > > > > or, with closure support: > > > > Arrays.sort(array, #(int a, int b) { > > a = Math.abs(a); b = Math.abs(b); > > return a < b ? -1 : a > b ? 1 : 0; > > }); > > > > In other words, convenient syntax, fast execution, while *keeping* the > > `Comparator` concept. Comparator cannot obviously be removed (it would > not > > be backwards compatible), and it would be inconsistent for the sorting > APIs > > to work with `Comparator` when sorting Objects, but to work with > `#int(int, > > int)` closures when trying to sort an array of primitive ints. > > > > ### §3 Curses! What about arrays! > > > > There's one case that this proposal has not yet covered: What happens > when > > `typearg_int` is used in an array? > > > > Let's say we have: > > > > public class Foo { > > protected T[] array = null; > > public abstract void method(T[] param); > > public abstract T[] returnType(); > > } > > > > What would happen if we tried to write: > > > > public class Bar extends Foo { > > @Override public void method(int[] param) { > > this.array = param; > > } > > > > @Override public int[] returnType() { > > return param; > > } > > } > > > > This question seems academic, in that generics and arrays almost never > meet, > > but that isn't quite true: `java.util.Collection` itself contains `public > > abstract T[] toList(T[] in);`. It is important to realize that > because > > arrays and generics are already convoluted when used together in java6, > the > > `T` in that signature is not related to the `E` of List itself (the `E` > in > > `public interface Collection`!). For usage in method declarations the > > wrapper methods can create a new array and copy each element, > > autoboxing/unboxing on the way. This is mind-bogglingly inefficient, but > it > > is simple. In practice the authors strongly suggest the implementer of > > `IntArrayList` write a specific method to get a straight `int[]` array > > without this convolution which obviously cannot be optimized by the VM > the > > way a single `int` to/from `Integer` conversion can be. For array access, > > the proposal suggests treating this concept as extremely rare and thus > > coming up with the simplest thing that could possibly work: Access to the > > array (read/write) is allowed and involves boxing as usual, but a > reference > > to `Foo.array` itself will simply remain its erased type and emits a > > warning. Therefore: > > > > public abstract class Bar extends Foo { > > void test() { > > Object[] o = array; //warning but legal > > int[] p = array; //error > > } > > } > > > > Nevertheless this concept introduces an API incompatibility: The javadoc > for > > `toList` states that if the input array has enough room, the same array > will > > be returned, and this cannot of course be done if the input array is > first > > number-for-number copied into a `Object[]` array, and then after the copy > > operation has completed, this array is translated back to `int[]`. This > > proposal offers no solution to this dilemma. It can only note that as > `int` > > is currently illegal in generics, it is technically backwards compatible > to > > add a note to the javadoc that explains the same array is *not* returned > > even if it has enough room if the type bound is a primitive. > > > > It also shows a gap in the API of a hypothetical `IntArrayList`: The > > signature (as mandated by the `Collection` interface) must be `public > > T[] toArray(T[] in)`, and as `T[]`'s erasure, which is `Object[]`, is not > > compatible with `int[]`, this method cannot be made fast even for a > specific > > subtype such as `IntArrayList`. This proposal offers no pragmatic > solution > > other than to create a custom method in `IntArrayList` as well as a > static > > utility method in `java.util.Collections` that can translate any list to > > `int[]`, which uses an instanceof check to pick up > > `java.util.ArrayList.IntArrayList`s special method and use that. > > > > The second issue raised is, in `public T[] toArray(T[] in)`, what > > happens if the calling code ends up binding `int` to `T`? This is a > > particularly painful process: Javac needs to generate the conversion from > > `int[]` to `Integer[]` prior to calling the method, and then the method > will > > most likely convert back to `int[]`, and on the return phase the same > double > > convert occurs for a grand total of 4 conversions. To avoid accidental > > triggering of this potentially very slow operation, a warning should be > > emitted anytime the compiler generates conversion code to convert a > > primitive array to a non-primitive array in order to fit with the erased > > signature of an invoked method. (For fields, as mentioned, the arrays > remain > > their erased type, and an attempt to treat them as primitive array > results > > in an error). > > > > > From abies at adres.pl Wed Mar 10 05:42:52 2010 From: abies at adres.pl (abies at adres.pl) Date: Wed, 10 Mar 2010 14:42:52 +0100 Subject: Primitives in Generics proposal. In-Reply-To: 560fb5ed1003100505k23bffe5dlb9f34742cae25a3@mail.gmail.com Message-ID: "Reinier Zwitserloot" napisa?(a): > I'll rebut point by point; > > 1: int[] <-> Integer[] conversion doesn't preserve reference identity. > > This rule has been broken before. In java 1.5, this assert isn't true, > because reference identity isn't maintained when boxing is applied: > > Integer x = new Integer(10000000); > int y = x; > Integer z = x; > assert z == x; //This will fail! There is a big difference - Integer is immutable. Array is inherently mutable and if you add it to some generic container and then mutate contents of that array through outside reference, internal copy will not be changed. Regards, Artur Biesiadowski From reinier at zwitserloot.com Wed Mar 10 06:29:39 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 10 Mar 2010 15:29:39 +0100 Subject: Primitives in Generics proposal. In-Reply-To: References: Message-ID: <560fb5ed1003100629u3d1823b9qba5567a6c21d55e8@mail.gmail.com> Excellent point, Arthur. Let's presume for now that if int[] <-> Integer[] conversion is required, an error is generated, until someone pulls a rabbit out of a hat. Not much is lost here; even with the (as Arthur pointed out too unwieldy) notion of converting arrays, List.toArray(new int[10]) was already ridiculously inefficient with all the conversion going on. toArray will remain to fill an object array with boxed Integer objects, and a special method would exist to turn List into int[]. Technically a VM change can allow any attempt to write into an array of component type I, if an array is actually given that is an object array, to let the VM do the boxing, and vice versa, but that's quite a step to take for JDK7. --Reinier Zwitserloot 2010/3/10 > > > "Reinier Zwitserloot" napisa?(a): > > I'll rebut point by point; > > > > 1: int[] <-> Integer[] conversion doesn't preserve reference identity. > > > > This rule has been broken before. In java 1.5, this assert isn't true, > > because reference identity isn't maintained when boxing is applied: > > > > Integer x = new Integer(10000000); > > int y = x; > > Integer z = x; > > assert z == x; //This will fail! > > There is a big difference - Integer is immutable. Array is inherently > mutable and if you add it to some generic container and then mutate contents > of that array through outside reference, internal copy will not be changed. > > Regards, > Artur Biesiadowski > From howard.lovatt at gmail.com Wed Mar 10 22:08:17 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 11 Mar 2010 17:08:17 +1100 Subject: A syntax option (function types versus arrays) Message-ID: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> There has been a long discussion about the syntax for lambdas and no solution has been found, this was expressed nicely by Josh Bloch: > I agree that it would be nice if we had something that nests better, and I'm > totally open to suggestion. But this alternative comes with many downsides: > surrounding a type in parens might appear tempting, but it really looks like > a cast to current-day Java programmers. As per my previous e-mail, I'm all > about designing a facility that is maximally readable, familiar, and > non-threatening to current-day Java programmers. Also the distinction between the lambda type and the lambda isn't clear (I think that both R?mi Forax and Reinier Zwitserloot have raised this issue - though you can't search Lambda Dev so I can't be certain it was them!). A possible alternate syntax is: #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); This syntax is in keeping with current Java, e.g.: #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); ArrayList< Integer > aList = new ArrayList< Integer >(); You can have arrays: #< R( A ) throws E >[] array = new #< R( A ) throws E >[ 1 ]; You can nest lambdas: #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = new #< #< R() throws E >( #< R( A ) throws E > l, A a ) >( l.( a ) ); The two specific suggestions embodied in the examples above are: 1. Mimic the method declaration syntax minus the method name, like the current proposal does, but enclose that within angle brackets, to mimic a generic declaration. 2. Require new to be used when you create a Lambda, to mimic current Java declarations and to clearly distinguish between the type and the creation. Comments? -- Howard. From howard.lovatt at gmail.com Wed Mar 10 22:29:57 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 11 Mar 2010 17:29:57 +1100 Subject: A syntax option (function types versus arrays) Message-ID: <3dd3f56a1003102229oad98683xc684364fdb10b281@mail.gmail.com> Oops, should read #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = new #< #< R() throws E >( #< R( A ) throws E > l, A a ) >( new #< R() throws E >()( l.( a ) ) ); Sorry, -- Howard. From mcnepp02 at googlemail.com Wed Mar 10 23:50:29 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Thu, 11 Mar 2010 07:50:29 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> Message-ID: <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> > > A possible alternate syntax is: > > #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); > I like the following two things about this syntax: firstly, the use of "new" to create a lambda. This makes it consistent with other object instantiations (in this case, an object of function type being created). secondly, the idea to re-use the syntax for parameterized types. However, I do not like these two things: firstly, as a matter of personal taste, the token sequence '#<' looks rather ugly, especially if nested. secondly, borrowing the syntax from generic type declarations seems half-hearted: there are still parentheses within the '<>' tokens. Why not go all the way to: lambda writer = new lambda { System.out.write(buf, off, len); } The keyword 'lambda' introduces the generic function type. At least one type variable must follow, indicating the return type. Further type variables may follow, indicating the argument types. Further type variables may follow the keyword 'throws', indicating the types of the checked Exceptions being thrown. From howard.lovatt at gmail.com Thu Mar 11 00:05:48 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 11 Mar 2010 19:05:48 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: <6FE42F7B-E2B7-4443-90AF-1E89CEB07E10@gmail.com> Yes, that is also a good suggestion, I have no real preference between the two forms. Note the round brackets around the arguments replace commas, so they are not really surpurfolous. -- Howard Lovatt +61 419 971 263 (sent from iPhone) On 11/03/2010, at 6:50 PM, Gernot Neppert wrote: >> >> A possible alternate syntax is: >> >> #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); >> > > I like the following two things about this syntax: > > firstly, the use of "new" to create a lambda. This makes it consistent > with other object instantiations (in this case, an object of function > type being created). > > secondly, the idea to re-use the syntax for parameterized types. > > However, I do not like these two things: > > firstly, as a matter of personal taste, the token sequence '#<' looks > rather ugly, especially if nested. > > secondly, borrowing the syntax from generic type declarations seems > half-hearted: there are still parentheses within the '<>' tokens. > > Why not go all the way to: > > lambda writer = new > lambda { > System.out.write(buf, off, len); > } > > The keyword 'lambda' introduces the generic function type. > At least one type variable must follow, indicating the return type. > Further type variables may follow, indicating the argument types. > Further type variables may follow the keyword 'throws', indicating the > types of the checked Exceptions being thrown. From alex.blewitt at gmail.com Thu Mar 11 00:09:51 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 11 Mar 2010 08:09:51 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: On 11 Mar 2010, at 07:50, Gernot Neppert wrote: >> >> A possible alternate syntax is: >> >> #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); > > I like the following two things about this syntax: > > firstly, the use of "new" to create a lambda. This makes it consistent > with other object instantiations (in this case, an object of function > type being created). However, it precludes the compiler from being able to optimise out instance creation in the case that the lambda is constant (or doesn't capture/use local state) since 'new' is defined semantically and by general understanding to create a new instance every time. What you really need is some kind of 'factory' that can either return you the same instance or give you a fresh instance each time depending on the circumstances. Enforcing an always-creation model would be a significant disadvantage for the kinds of filters (like 'even') which would not change each time. Alex From mcnepp02 at googlemail.com Thu Mar 11 00:30:54 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Thu, 11 Mar 2010 08:30:54 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: <1f5b87141003110030n50d0f504x8d9245c537a5bf8e@mail.gmail.com> >> I like the following two things about this syntax: >> >> firstly, the use of "new" to create a lambda. This makes it consistent >> with other object instantiations (in this case, an object of function >> type being created). > > However, it precludes the compiler from being able to optimise out instance creation in the case that the lambda is constant (or doesn't capture/use local state) since 'new' is defined semantically and by general understanding to create a new instance every time. > Of course, if you intend to make lambda creation special with regards to automatic instance caching by the compiler, using 'new' is not a good idea. OTOH, is this really necessary? I have confidence that the capable library developer will identify stateless, non-capturing lambdas herself and provide factories for them or store them in static fields (akin to String.CASE_INSENSITIVE_COMPARE): lambda,Iterable> even = IntegerFilters.EVEN; From mcnepp02 at googlemail.com Thu Mar 11 00:56:48 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Thu, 11 Mar 2010 08:56:48 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <6FE42F7B-E2B7-4443-90AF-1E89CEB07E10@gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <6FE42F7B-E2B7-4443-90AF-1E89CEB07E10@gmail.com> Message-ID: <1f5b87141003110056j744494e4g3cd2a8aa6ddf01d5@mail.gmail.com> 2010/3/11 Howard Lovatt : > Yes, that is also a good suggestion, I have no real preference between the > two forms. Note the round brackets around the arguments replace commas, so > they are not really surpurfolous. > Yes, I know. Of course your proposal is totally consistent in its own right. I just found the approach a bit 'hybrid': it surrounds the expression deonoting the lambda's types within angular brackets, but then introduces a different style for this expression, using round brackets for the arguments. Note that with your proposal the signature for a 'Runnable-like' lambda becomes: lambda runnable = new lambda { System.out.println("Hello world!"); }; which, to my eyes, looks arguably less elegant than the equivalent with my proposal: lambda runnable = new lambda { System.out.println("Hello world!"); }; Simply because the first type variable denotes the return type 'void', having no need for the empty parentheses. From alex.blewitt at gmail.com Thu Mar 11 01:07:40 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 11 Mar 2010 09:07:40 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003110030n50d0f504x8d9245c537a5bf8e@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <1f5b87141003110030n50d0f504x8d9245c537a5bf8e@mail.gmail.com> Message-ID: On 11 Mar 2010, at 08:30, Gernot Neppert wrote: >>> I like the following two things about this syntax: >>> >>> firstly, the use of "new" to create a lambda. This makes it consistent >>> with other object instantiations (in this case, an object of function >>> type being created). >> >> However, it precludes the compiler from being able to optimise out instance creation in the case that the lambda is constant (or doesn't capture/use local state) since 'new' is defined semantically and by general understanding to create a new instance every time. > > Of course, if you intend to make lambda creation special with regards > to automatic instance caching by the compiler, using 'new' is not a > good idea. OTOH, is this really necessary? > I have confidence that the capable library developer will identify > stateless, non-capturing lambdas herself and provide factories for > them or store them in static fields. This is essential, yes. The majority of 'capable library developers' may not, but the majority of Java developers using lambdas for the first time may well do so. You'd like the compiler to do that for you. Alex From jp at hapra.at Thu Mar 11 00:52:10 2010 From: jp at hapra.at (Jakob Praher) Date: Thu, 11 Mar 2010 09:52:10 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: <4B98AF3A.9030102@hapra.at> Gernot Neppert schrieb: > Why not go all the way to: > > lambda writer = new > lambda { > System.out.write(buf, off, len); > } > IMHO: It is far better to prefix the types with some letters than with a #. Yet the question is if the type of the lambda is a lambda or if the type is a function. If an we choose an ID why not name the type: * fun writer = ... Nesting is then: * fun< fun (String ) throws Throwable > writerLookup = ... What do you think? The parenthesis reflect the argument signature and help with respect to nesting. -- Jakob From alex.blewitt at gmail.com Thu Mar 11 01:29:48 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 11 Mar 2010 09:29:48 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B98AF3A.9030102@hapra.at> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <4B98AF3A.9030102@hapra.at> Message-ID: <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> On 11 Mar 2010, at 08:52, Jakob Praher wrote: > Gernot Neppert schrieb: >> Why not go all the way to: >> >> lambda... > IMHO: It is far better to prefix the types with some letters than with a #. OK, I'll point out the obvious. any 'some letters' are currently a valid identifier in Java, and you can't guarantee that there's no-one in the world who hasn't used the identifier 'lambda' before. So pretty much any construct needs to be either one of the unused keywords in the existing Java language spec (e.g. goto) or something that currently isn't semantically correct in an existing Java program as an identifier (hence the #). That's not to say that necessarily # has to be the only other choice, but introducing a new keyword based on existing (potentially common) words is likely to cause issues. Alex From jp at hapra.at Thu Mar 11 01:15:18 2010 From: jp at hapra.at (Jakob Praher) Date: Thu, 11 Mar 2010 10:15:18 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: <4B98B4A6.6000206@hapra.at> Gernot Neppert schrieb: > Why not go all the way to: > > lambda writer = new > lambda { > System.out.write(buf, off, len); > } > IMHO: It is far better to prefix the types with some letters than with a #. Yet the question is if the type of the lambda is a lambda or if the type is a function. If an we choose an ID why not name the type: * fun writer = ... Nesting is then: * fun< fun (String ) throws Throwable > writerLookup = ... What do you think? The parenthesis reflect the argument signature and help with respect to nesting. -- Jakob From jp at hapra.at Thu Mar 11 01:55:41 2010 From: jp at hapra.at (Jakob Praher) Date: Thu, 11 Mar 2010 10:55:41 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <4B98AF3A.9030102@hapra.at> <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> Message-ID: <4B98BE1D.7040508@hapra.at> Alex Blewitt schrieb: > On 11 Mar 2010, at 08:52, Jakob Praher wrote: > > OK, I'll point out the obvious. any 'some letters' are currently a valid identifier in Java, and you can't guarantee that there's no-one in the world who hasn't used the identifier 'lambda' before. So pretty much any construct needs to be either one of the unused keywords in the existing Java language spec (e.g. goto) or something that currently isn't semantically correct in an existing Java program as an identifier (hence the #). That's not to say that necessarily # has to be the only other choice, but introducing a new keyword based on existing (potentially common) words is likely to cause issues. > Sure that is clear. This was a sentiment to favor a readable letter (this is why I am still convinced that adding declaration-site variance would be best, since then you do not need any keyword at all), not a demand to carelessly introduce a new keyword. If we use an identifier/keyword it MUST convey the right semantics.IMHO the type of a lambda is a function/callable. In computer science theory lambda is a concept for expressing computation, but in Java in its current form it is a synonym for anonymous function with variable capture from the enclosing lexical scope. Remeber that a lambda is the project name: http://blogs.sun.com/mr/entry/closures_qa#comment-1259799344000 I do want to use methods as functions too without having to call them lambdas. Sure most of them end up capturing instances away, but in the formal parameters it should called a function or callable or invokable. void filter (Function1 x); void filter (lambda x); void filter (func x); In function based on the typed lambda calulus (e.g. Haskell) on also uses lambda expressions to create anonymous functions. The type of a lambda expression is a function. See also FCM: http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc -- Jakob > > From reinier at zwitserloot.com Thu Mar 11 04:52:49 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Thu, 11 Mar 2010 13:52:49 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B98BE1D.7040508@hapra.at> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <4B98AF3A.9030102@hapra.at> <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> <4B98BE1D.7040508@hapra.at> Message-ID: <560fb5ed1003110452s2c40c104ve0cea814eb457ccf@mail.gmail.com> Lambda sounds pretty good to us but does Joe Average like it? Java doesn't use the terms co/contravariance anywhere in the syntax either. Is Joe Average going to call these things "lambdas"? Why would they know the term? Why should they know the term? "Closure", even if its somewhat of a misnomer perhaps, is a far more commonly used term in the java community outside of the Project Lambda mailing list. Of course, it _is_ a bit of a misnomer so using a (limited) keyword "closure" is not the right answer either. >From a parser perspective, any keyword such as "lambda" needs special treatment; in something like: int lambda = lambda; The term 'lambda' is a standard identifier and *NOT* a keyword, lest backwards compatibility is lost, which is a capital offense. I fear that this is going to lead to the parser generating obscure and generally wildly off-base errors when you mistype a lambda expression and it ends up looking like you are using 'lambda' as identifier and not a keyword. You'd have to weigh all these issues against the "this feels a bit like perl cartoon swearing syndrome" that introducing the "#" gives us, and to me its starting to look like the # is going to win this particular battle. Yes, perl cartoon swearing syndrome is bad, but the other side of this equation is worse. Gut instinct reaction to <> syntax: Not too bad actually. It is indeed a bit more consistent in that currently grouping types together is done with <> in generics and never with (). There are casts, but that's not really 'grouping' types. --Reinier Zwitserloot On Thu, Mar 11, 2010 at 10:55 AM, Jakob Praher wrote: > Alex Blewitt schrieb: > > On 11 Mar 2010, at 08:52, Jakob Praher wrote: > > > > OK, I'll point out the obvious. any 'some letters' are currently a valid > identifier in Java, and you can't guarantee that there's no-one in the world > who hasn't used the identifier 'lambda' before. So pretty much any construct > needs to be either one of the unused keywords in the existing Java language > spec (e.g. goto) or something that currently isn't semantically correct in > an existing Java program as an identifier (hence the #). That's not to say > that necessarily # has to be the only other choice, but introducing a new > keyword based on existing (potentially common) words is likely to cause > issues. > > > Sure that is clear. This was a sentiment to favor a readable letter > (this is why I am still convinced that adding declaration-site variance > would be best, since then you do not need any keyword at all), not a > demand to carelessly introduce a new keyword. > > If we use an identifier/keyword it MUST convey the right semantics.IMHO > the type of a lambda is a function/callable. In computer science theory > lambda is a concept for expressing computation, but in Java in its > current form it is a synonym for anonymous function with variable > capture from the enclosing lexical scope. > > Remeber that a lambda is the project name: > http://blogs.sun.com/mr/entry/closures_qa#comment-1259799344000 > > I do want to use methods as functions too without having to call them > lambdas. Sure most of them end up capturing instances away, but in the > formal parameters it should called a function or callable or invokable. > > void filter (Function1 x); > void filter (lambda x); > void filter (func x); > > In function based on the typed lambda calulus (e.g. Haskell) on also > uses lambda expressions to create anonymous functions. The type of a > lambda expression is a function. > > See also FCM: http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc > > -- Jakob > > > > > > > From jkuhnert at gmail.com Thu Mar 11 06:24:56 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Thu, 11 Mar 2010 09:24:56 -0500 Subject: A syntax option (function types versus arrays) In-Reply-To: <560fb5ed1003110452s2c40c104ve0cea814eb457ccf@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <4B98AF3A.9030102@hapra.at> <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> <4B98BE1D.7040508@hapra.at> <560fb5ed1003110452s2c40c104ve0cea814eb457ccf@mail.gmail.com> Message-ID: <7926817e1003110624q362e90d0ua2c22ae7e8be6f9@mail.gmail.com> I think both the "new" and "lambda" keywords sound kind of ridiculous for obvious reasons. They should be viewed as "blocks" and blocks currently use {} to denote their boundaries. This isn't as complicated to understand as everyone seems to think. I'd imagine a lot of java developers have done some web development at some point, and of those that have I'd guess that a good number have had to program in javascript or similar. Introducing them as "blocks" with special behavior probably makes some sense, outside of calling them closures. All this hand wringing may really be for naught. On Thu, Mar 11, 2010 at 7:52 AM, Reinier Zwitserloot wrote: > Lambda sounds pretty good to us but does Joe Average like it? Java doesn't > use the terms co/contravariance anywhere in the syntax either. Is Joe > Average going to call these things "lambdas"? Why would they know the term? > Why should they know the term? "Closure", even if its somewhat of a misnomer > perhaps, is a far more commonly used term in the java community outside of > the Project Lambda mailing list. Of course, it _is_ a bit of a misnomer so > using a (limited) keyword "closure" is not the right answer either. > > >From a parser perspective, any keyword such as "lambda" needs special > treatment; in something like: > > > int lambda = lambda; > > The term 'lambda' is a standard identifier and *NOT* a keyword, lest > backwards compatibility is lost, which is a capital offense. I fear that > this is going to lead to the parser generating obscure and generally wildly > off-base errors when you mistype a lambda expression and it ends up looking > like you are using 'lambda' as identifier and not a keyword. > > You'd have to weigh all these issues against the "this feels a bit like perl > cartoon swearing syndrome" that introducing the "#" gives us, and to me its > starting to look like the # is going to win this particular battle. Yes, > perl cartoon swearing syndrome is bad, but the other side of this equation > is worse. > > Gut instinct reaction to <> syntax: Not too bad actually. It is indeed a bit > more consistent in that currently grouping types together is done with <> in > generics and never with (). There are casts, but that's not really > 'grouping' types. > > > > --Reinier Zwitserloot > > > > On Thu, Mar 11, 2010 at 10:55 AM, Jakob Praher wrote: > >> Alex Blewitt schrieb: >> > On 11 Mar 2010, at 08:52, Jakob Praher wrote: >> > >> > OK, I'll point out the obvious. any 'some letters' are currently a valid >> identifier in Java, and you can't guarantee that there's no-one in the world >> who hasn't used the identifier 'lambda' before. So pretty much any construct >> needs to be either one of the unused keywords in the existing Java language >> spec (e.g. goto) or something that currently isn't semantically correct in >> an existing Java program as an identifier (hence the #). ?That's not to say >> that necessarily # has to be the only other choice, but introducing a new >> keyword based on existing (potentially common) words is likely to cause >> issues. >> > >> Sure that is clear. This was a sentiment to favor a readable letter >> (this is why I am still convinced that adding declaration-site variance >> would be best, since then you do not need any keyword at all), not a >> demand to carelessly introduce a new keyword. >> >> If we use an identifier/keyword it MUST convey the right semantics.IMHO >> the type of a lambda is a function/callable. In computer science theory >> lambda is a concept for expressing computation, but in Java in its >> current form it is a synonym for anonymous function with variable >> capture from the enclosing lexical scope. >> >> Remeber that a lambda is the project name: >> http://blogs.sun.com/mr/entry/closures_qa#comment-1259799344000 >> >> I do want to use methods as functions too without having to call them >> lambdas. Sure most of them end up capturing instances away, but in the >> formal parameters it should called a function or callable or invokable. >> >> void filter (Function1 x); >> void filter (lambda x); >> void filter (func x); >> >> In function based on the typed lambda calulus (e.g. Haskell) on also >> uses lambda expressions to create anonymous functions. The type of a >> lambda expression is a function. >> >> See also FCM: http://docs.google.com/Doc?id=ddhp95vd_6hg3qhc >> >> -- Jakob >> > >> > >> >> >> > > From Joe.Darcy at Sun.COM Thu Mar 11 09:26:47 2010 From: Joe.Darcy at Sun.COM (Joseph D. Darcy) Date: Thu, 11 Mar 2010 09:26:47 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> Message-ID: <4B9927D7.9020407@sun.com> Howard Lovatt wrote: > There has been a long discussion about the syntax for lambdas and no > solution has been found, this was expressed nicely by Josh Bloch: > > >> I agree that it would be nice if we had something that nests better, and I'm >> totally open to suggestion. But this alternative comes with many downsides: >> surrounding a type in parens might appear tempting, but it really looks like >> a cast to current-day Java programmers. As per my previous e-mail, I'm all >> about designing a facility that is maximally readable, familiar, and >> non-threatening to current-day Java programmers. >> > > Also the distinction between the lambda type and the lambda isn't > clear (I think that both R?mi Forax and Reinier Zwitserloot have > raised this issue - though you can't search Lambda Dev so I can't be > certain it was them!). > Using "site:http://mail.openjdk.java.net/pipermail/lambda-dev" with a popular search engine makes the mailing list searchable. -Joe From jjb at google.com Thu Mar 11 10:01:37 2010 From: jjb at google.com (Joshua Bloch) Date: Thu, 11 Mar 2010 10:01:37 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B9927D7.9020407@sun.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> Message-ID: <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> My two cents: #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = new #< #( #< R( A ) throws E > l, A a ) >( l.( a ) ); Nesting is nice, but: - The angle brackets will remind people of generics, which won't make them happy. - Angle brackets are a poor man's parentheses, because they do double duty as unmatched operators (less than and greater than). - The pound-sign+left-angle-bracket combo (#<) isn't exactly easy on the eyes. - The new keyword will be viewed as exactly the kind of boilerplate that this effort was designed to eliminate. I do think it makes sense to explore new syntax proposals, but I'm not sure I like this one better than the one that's currently on the table. Josh From serge.boulay at gmail.com Thu Mar 11 11:33:12 2010 From: serge.boulay at gmail.com (Serge Boulay) Date: Thu, 11 Mar 2010 14:33:12 -0500 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> Message-ID: <855b507d1003111133q4bd761dv5322f7439a3c16c7@mail.gmail.com> .net has something similar to what you describe. Take a look at Func<> and Action<> On Thu, Mar 11, 2010 at 1:08 AM, Howard Lovatt wrote: > There has been a long discussion about the syntax for lambdas and no > solution has been found, this was expressed nicely by Josh Bloch: > > > I agree that it would be nice if we had something that nests better, and > I'm > > totally open to suggestion. But this alternative comes with many > downsides: > > surrounding a type in parens might appear tempting, but it really looks > like > > a cast to current-day Java programmers. As per my previous e-mail, I'm > all > > about designing a facility that is maximally readable, familiar, and > > non-threatening to current-day Java programmers. > > Also the distinction between the lambda type and the lambda isn't > clear (I think that both R?mi Forax and Reinier Zwitserloot have > raised this issue - though you can't search Lambda Dev so I can't be > certain it was them!). > > A possible alternate syntax is: > > #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); > > This syntax is in keeping with current Java, e.g.: > > #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); > ArrayList< Integer > aList = new ArrayList< Integer >(); > > You can have arrays: > > #< R( A ) throws E >[] array = new #< R( A ) throws E >[ 1 ]; > > You can nest lambdas: > > #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = new #< #< > R() throws E >( #< R( A ) throws E > l, A a ) >( l.( a ) ); > > > > The two specific suggestions embodied in the examples above are: > > 1. Mimic the method declaration syntax minus the method name, like the > current proposal does, but enclose that within angle brackets, to > mimic a generic declaration. > > 2. Require new to be used when you create a Lambda, to mimic current > Java declarations and to clearly distinguish between the type and the > creation. > > Comments? > > -- Howard. > > From john at milsson.nu Thu Mar 11 11:37:17 2010 From: john at milsson.nu (John Nilsson) Date: Thu, 11 Mar 2010 20:37:17 +0100 Subject: Inverted syntax option Message-ID: Most syntax proposals so far has been variants of specifying the type and arguments of the lambda to be created. I have another suggestion, inverted lambdas. My suggestion is to focus on the current expression syntax of Java and just tweak it a little bit to allow parameters. So any valid Java expression is a lambda if it contains an identifier of the form # where denotes the position in the argument list. Examples. (I have borrowed Neals type syntax, but my suggestion is just about the expression syntax) (int,int) -> int adder = #1 + #2; int sum = intList.reduce(adder); int sum2 = intList.reduce(#1 + #2); When the type of an identifier is not known it defaults to Object Object expr = #1.method(); //Compiler error, method is not a member of Object Object expr2 = ((MyClass)#1).method(); //Typical cast already known to Java-developers. Object expr3 = ((MyClass)->Void) #1.method(); //This is also valid version BR, John From neal at gafter.com Thu Mar 11 12:36:50 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 11 Mar 2010 12:36:50 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <855b507d1003111133q4bd761dv5322f7439a3c16c7@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <855b507d1003111133q4bd761dv5322f7439a3c16c7@mail.gmail.com> Message-ID: <15e8b9d21003111236q6fd89011h7e5df98519b8746d@mail.gmail.com> On Thu, Mar 11, 2010 at 11:33 AM, Serge Boulay wrote: > .net has something similar to what you describe. Take a look at ?Func<> and > Action<> Yes, Scala too. That's possible if your language has declaration-site variance (as Scala and C# have), and allows all types in generics, but Java does not have either. In any case, I can tell you from personal experience that the syntax is not particularly readable. From schulz at the-loom.de Thu Mar 11 13:59:42 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Thu, 11 Mar 2010 22:59:42 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> Message-ID: <4B9967CE.7010306@the-loom.de> On 11.03.2010 19:01, Joshua Bloch wrote: > My two cents: > > #< #< R() throws E>( #< R( A ) throws E>, A )> curry = > new #< #( #< R( A ) throws E> l, A a )>( l.( a ) ); > > (..) > > I do think it makes sense to explore new syntax proposals, but I'm not sure > I like this one better than the one that's currently on the table. Adding another two cents. The use of hash plus angle brackets plus round parens gives quite some noise. I imagine adding some parameterized types in such a definition ... I scanned the list and noted down the syntax proposals we have so far (order of appearance on the list) using a simplyfied notation (ignoring optional definitions). I also added a curry-example to each of them, which I hopefully got right. Cheers, Stefan 1) Straw-man, latest # ResultType ( TypeList ) ( throws ExceptionList ) Curry-example: ##R()(throws E) (#R(A)(throws E), A) curry = ... 2) Peter Levart, 26 Jan 2010 # ( TypeList : ResultType throws ExceptionList ) Curry-example: #( #(A: R throws E), A: #(: R throws E) ) curry = ... 3) John Rose, 26 Jan 2010 ff ( TypeList ) throws PipedExceptionList -> ResultType Curry-example: ((A) throws E -> R, A) -> () throws E -> R curry = ... 4) Neal Gafter, 27 Jan 2010 # ( TypeList -> ResultType throws ExceptionList ) Curry-example: #(#(A -> R throws E), A) -> #( -> R throws E)) curry = ... 5) Stefan Schulz, 31 Jan 2010 [ ResultType ( TypeList ) throws ExceptionList ] Curry-example: [[R() throws E]([R(A) throws E], A) curry = ... 6) Remi Forax, 09 Feb 2010 TypeList throws ExceptionList -> ResultType (plus additional parens rules) Curry-Example: (A throws E -> R), A -> (throws E -> R) curry = ... 7) Peter Levart, 9 Feb 2010 ReturnType # ( TypeList ) throws ExceptionList Curry-Example: R #() throws E #(R #(A) throws E, A) curry = ... 8) Stefan Schulz, 16 Feb 2010 (: TypeList -> ResultType throws ExceptionList ) Curry-Example: (: (: A -> R throws E ), A -> (: -> R throws E) ) curry = ... 9) Neal Gafter, 26 Feb 2010 ( TypeList throws ExceptionList ) -> ResultType Curry-Example: ( (A throws E) -> R, A ) -> (throws E) -> R curry = ... 10) BGGA { TypeList => ResultType throws ExceptionList } Curry-example: { {A => R throws E}, A => { => R throws E} } curry = ... 11) FCM # ( ResultType ( TypeList ) throws ExceptionList ) Curry-example: #( #(R() throws E) ( #(R(A) throws E), A ) ) curry = ... 12) FCM Alternate # ( TypeList return ResultType throws ExceptionList ) Curry-example: #( #(A return R throws E), A return #(return R throws E)) curry = ... 13) Howard Lovatt, 11 Mar 2010 # < ResultType ( TypeList ) throws ExceptionList > Curry-example: #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = ... 14) Gernot Neppert, 11 Mar 2010 lambda < ReturnType , TypeList , throws ExceptionList > Curry-example: lambda, lambda, A> curry = ... From howard.lovatt at gmail.com Thu Mar 11 14:58:30 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 09:58:30 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> Message-ID: <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> I am not sure it does preclude the JVM from optimizing the instance creation, some JVMs do currently optimize away object allocation when they can. To me this is another possible optimization. There is an advantage in spelling out that you have an expensive operation in that people are more likely to be aware of a potential problem and hence avoid it in the first place, e.g.: for ( final int[] row : matrix ) { filteredAddAll( result, row, new #< boolean( final int x ) >( x % 2 == 0) ); } Is likely to be spotted by the programmer because of the new and therefore they are likely to refactor it themselves: final #< boolean( int ) > even = new #< boolean( final int x ) >( x % 2 == 0); for ( final int[] row : matrix ) { filteredAddAll( result, row, even ); } Which is nice, since people are then understanding what is actually happening. On 11 March 2010 19:09, Alex Blewitt wrote: > On 11 Mar 2010, at 07:50, Gernot Neppert wrote: > >>> >>> A possible alternate syntax is: >>> >>> #< R( A ) throws E > example = new #< R( A a ) throws E >( ... ); >> >> I like the following two things about this syntax: >> >> firstly, the use of "new" to create a lambda. This makes it consistent >> with other object instantiations (in this case, an object of function >> type being created). > > However, it precludes the compiler from being able to optimise out instance creation in the case that the lambda is constant (or doesn't capture/use local state) since 'new' is defined semantically and by general understanding to create a new instance every time. > > What you really need is some kind of 'factory' that can either return you the same instance or give you a fresh instance each time depending on the circumstances. Enforcing an always-creation model would be a significant disadvantage for the kinds of filters (like 'even') which would not change each time. > > Alex -- -- Howard. From john at milsson.nu Thu Mar 11 15:14:46 2010 From: john at milsson.nu (John Nilsson) Date: Fri, 12 Mar 2010 00:14:46 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> Message-ID: On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt wrote: > There is an advantage in spelling out that you have an expensive > operation in that people are more likely to be aware of a potential > problem and hence avoid it in the first place > But it is only expensive if you assume a broken compiler or VM. There is nothing inherent in the language to suggest that it should be expensive. BR, John From alex.blewitt at gmail.com Thu Mar 11 15:22:29 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 11 Mar 2010 23:22:29 +0000 Subject: A syntax option (function types versus arrays) In-Reply-To: References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> Message-ID: <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> On 11 Mar 2010, at 23:14, John Nilsson wrote: > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt wrote: > There is an advantage in spelling out that you have an expensive > operation in that people are more likely to be aware of a potential > problem and hence avoid it in the first place > > But it is only expensive if you assume a broken compiler or VM. There is nothing inherent in the language to suggest that it should be expensive. If you specify 'new' then the runtime VM is forced to lay out space for the new data as well as return a fresh instance: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#41147 Next, space is allocated for the new class instance. Every time the expression is evaluated, a fresh object is created So by using the keyword 'new' - and assuming unchanged semantics in this area of the JLS - then you are going to at least cycle through the new generation even if the runtime JIT may be able to optimise it away in certain circumstances. However, if the keyword 'new' is not used then these issues do not apply. Alex From jkuhnert at gmail.com Thu Mar 11 16:24:09 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Thu, 11 Mar 2010 19:24:09 -0500 Subject: A syntax option (function types versus arrays) In-Reply-To: <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> Message-ID: <7926817e1003111624y318506fem4bebeca0d7348ff3@mail.gmail.com> Now that we've established what 'new' means, any hints from the people that know what they're doing where the project is heading? Probably wierd timing, so maybe better to be patient on this one. On Thursday, March 11, 2010, Alex Blewitt wrote: > On 11 Mar 2010, at 23:14, John Nilsson wrote: > >> On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt wrote: >> There is an advantage in spelling out that you have an expensive >> operation in that people are more likely to be aware of a potential >> problem and hence avoid it in the first place >> >> But it is only expensive if you assume a broken compiler or VM. There is nothing inherent in the language to suggest that it should be expensive. > > If you specify 'new' then the runtime VM is forced to lay out space for the new data as well as return a fresh instance: > > http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#41147 > > Next, space is allocated for the new class instance. Every time the expression is evaluated, a fresh object is created > > So by using the keyword 'new' - and assuming unchanged semantics in this area of the JLS - then you are going to at least cycle through the new generation even if the runtime JIT may be able to optimise it away in certain circumstances. > > However, if the keyword 'new' ?is not used then these issues do not apply. > > Alex > > From neal at gafter.com Thu Mar 11 16:38:20 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 11 Mar 2010 16:38:20 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <7926817e1003111624y318506fem4bebeca0d7348ff3@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> <7926817e1003111624y318506fem4bebeca0d7348ff3@mail.gmail.com> Message-ID: <15e8b9d21003111638u5e63472di986bdc12fe4fefac@mail.gmail.com> On Thu, Mar 11, 2010 at 4:24 PM, Jesse Kuhnert wrote: > Now that we've established what 'new' means, any hints from the people > that know what they're doing where the project is heading? Alex Buckley was pretty clear that the lambda specification should not dictate when the allocation occurs. That is nearly the same thing as not dictating that each invocation of a lambda expression results in a distinct value. In other words, it conflicts with the meaning of 'new'. This does not work for the conversion to SAM classes, as user code executes to perform the construction. That must be visible at compile time (checked exception checking for exceptions thrown by the constructor) and runtime (the constructor code executes). We have yet to see how project lambda will address that dilemma So far there is no proposed syntax for the lambda conversion into which "new" could be shoehorned. From howard.lovatt at gmail.com Thu Mar 11 21:56:09 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 16:56:09 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <4B98AF3A.9030102@hapra.at> <3212C2A0-A83D-4136-A3EC-708E6B799014@gmail.com> Message-ID: <3dd3f56a1003112156h74efa674l5655bcc9c8616d77@mail.gmail.com> You can have an identifier rather than a symbol if you add class Lambda to java.lang then you could write: Lambda< R( A ) throws E > lambda = new Lambda< R( A a ) throws E >( ... ); This is very similar to what is proposed for class MethodHandle, so it would be consistent with JSR 292. On 11 March 2010 20:29, Alex Blewitt wrote: > On 11 Mar 2010, at 08:52, Jakob Praher wrote: > >> Gernot Neppert schrieb: >>> Why not go all the way to: >>> >>> lambda... >> IMHO: It is far better to prefix the types with some letters than with a #. > > OK, I'll point out the obvious. any 'some letters' are currently a valid identifier in Java, and you can't guarantee that there's no-one in the world who hasn't used the identifier 'lambda' before. So pretty much any construct needs to be either one of the unused keywords in the existing Java language spec (e.g. goto) or something that currently isn't semantically correct in an existing Java program as an identifier (hence the #). ?That's not to say that necessarily # has to be the only other choice, but introducing a new keyword based on existing (potentially common) words is likely to cause issues. > > Alex > > > > -- -- Howard. From howard.lovatt at gmail.com Thu Mar 11 22:00:21 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 17:00:21 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B9927D7.9020407@sun.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> Message-ID: <3dd3f56a1003112200m7585d629ib373846c8d2a5eea@mail.gmail.com> Thanks - I will do that in future On 12 March 2010 04:26, Joseph D. Darcy wrote: > Howard Lovatt wrote: >> >> There has been a long discussion about the syntax for lambdas and no >> solution has been found, this was expressed nicely by Josh Bloch: >> >> >>> >>> I agree that it would be nice if we had something that nests better, and >>> I'm >>> totally open to suggestion. ?But this alternative comes with many >>> downsides: >>> surrounding a type in parens might appear tempting, but it really looks >>> like >>> a cast to current-day Java programmers. ?As per my previous e-mail, I'm >>> all >>> about designing a facility that is maximally readable, familiar, and >>> non-threatening to current-day Java programmers. >>> >> >> Also the distinction between the lambda type and the lambda isn't >> clear (I think that both R?mi Forax and Reinier Zwitserloot have >> raised this issue - though you can't search Lambda Dev so I can't be >> certain it was them!). >> > > Using "site:http://mail.openjdk.java.net/pipermail/lambda-dev" with a > popular search engine makes the mailing list searchable. > > -Joe > -- -- Howard. From howard.lovatt at gmail.com Thu Mar 11 22:09:53 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 17:09:53 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> Message-ID: <3dd3f56a1003112209o5a4e7926y9ddda3757c2ca9e7@mail.gmail.com> Comments in line On 12 March 2010 05:01, Joshua Bloch wrote: > My two cents: > #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = > ?? ?new #< #( #< R( A ) throws E > l, A a ) >( l.( a ) ); > Nesting is nice, but: > > The angle brackets will remind people of generics, which won't make them > happy. It is type information, just like generics, therefore angle brackets are the consistent choice. > Angle brackets are a poor man's parentheses, because they do double duty as > unmatched operators (less than and greater than). Yes, but we already have them from generics so we are stuck with that double use > The pound-sign+left-angle-bracket combo (#<) isn't exactly easy on the eyes. Could use Lambda instead of # > The new keyword will be viewed as exactly the kind of boilerplate that this > effort was designed to eliminate. Yes, but people also won't like the inconsistency of normal classes requiring new and lambdas specifically not allowing new. A further advantage of new is that it makes SAM types easier since you know where the constructor is called. > I do think it makes sense to explore new syntax proposals, but I'm not sure > I like this one better than the one that's currently on the table. > ?? ? ? ? ?Josh -- Howard. From howard.lovatt at gmail.com Thu Mar 11 22:12:52 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 17:12:52 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> Message-ID: <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> All the implementations suggested to date require at least one new object per lambda, so new is signaling that an object will in all likely hood be created (unless the JVM can eliminate it). On 12 March 2010 10:14, John Nilsson wrote: > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt > wrote: >> >> There is an advantage in spelling out that you have an expensive >> operation in that people are more likely to be aware of a potential >> problem and hence avoid it in the first place > > > But it is only expensive if you assume a broken compiler or VM. There is > nothing inherent in the language to suggest that it should be expensive. > BR, > John -- -- Howard. From howard.lovatt at gmail.com Thu Mar 11 22:16:36 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 17:16:36 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> Message-ID: <3dd3f56a1003112216n4db0f491s6442b045397419d2@mail.gmail.com> My understanding is that the JVM is free to optimize object creation away as long as it can convince itself that the effect cannot be observed, hence the escape analysis proposed that will stack allocate instead of heap allocate. On 12 March 2010 10:22, Alex Blewitt wrote: > On 11 Mar 2010, at 23:14, John Nilsson wrote: > > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt > wrote: >> >> There is an advantage in spelling out that you have an expensive >> operation in that people are more likely to be aware of a potential >> problem and hence avoid it in the first place > > > But it is only expensive if you assume a broken compiler or VM. There is > nothing inherent in the language to suggest that it should be expensive. > > If you specify 'new' then the runtime VM is forced to lay out space for the > new data as well as return a fresh instance: > http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#41147 > Next, space is allocated for the new class instance.?Every time the > expression is evaluated, a fresh object is created > So by using the keyword 'new' - and assuming unchanged semantics in this > area of the JLS - then you are going to at least cycle through the new > generation even if the runtime JIT may be able to optimise it away in > certain circumstances. > However, if the keyword 'new' ?is not used then these issues do not apply. > Alex -- -- Howard. From howard.lovatt at gmail.com Thu Mar 11 22:49:54 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 12 Mar 2010 17:49:54 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003111638u5e63472di986bdc12fe4fefac@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> <7926817e1003111624y318506fem4bebeca0d7348ff3@mail.gmail.com> <15e8b9d21003111638u5e63472di986bdc12fe4fefac@mail.gmail.com> Message-ID: <3dd3f56a1003112249q74604f78i5db540f0e873e426@mail.gmail.com> If new were used, as suggested, then it would make SAM types easier since the point of creation would be known, which is desirable for SAMs. You could go further and allow short syntax for SAMs instead of lambda conversion to SAMs, i.e.: Runnable run = new #Runnable() ( expression ); Again the new, if used in lambdas, would aid consistency across similar declarations: #< void() > lam = new #< void() > ( expression ); Runnable run = new #Runnable() ( expression ); Runnable run = new Runnable() { public void run() { return expression; } }; For completeness an example with generics: Callable< Void > call = new #Callable< Void >() ( expression ); (This suggestion above for SAMs is obviously similar to the CICE proposal and also similar to comments Josh Bloch has made on this forum.) On 12 March 2010 11:38, Neal Gafter wrote: > On Thu, Mar 11, 2010 at 4:24 PM, Jesse Kuhnert wrote: >> Now that we've established what 'new' means, any hints from the people >> that know what they're doing where the project is heading? > > Alex Buckley was pretty clear that the lambda specification should not > dictate when the allocation occurs. ?That is nearly the same thing as > not dictating that each invocation of a lambda expression results in a > distinct value. ?In other words, it conflicts with the meaning of > 'new'. > > This does not work for the conversion to SAM classes, as user code > executes to perform the construction. ?That must be visible at compile > time (checked exception checking for exceptions thrown by the > constructor) and runtime (the constructor code executes). ?We have yet > to see how project lambda will address that dilemma ?So far there is > no proposed syntax for the lambda conversion into which "new" could be > shoehorned. > -- -- Howard. From neal at gafter.com Thu Mar 11 22:54:35 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 11 Mar 2010 22:54:35 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> Message-ID: <15e8b9d21003112254lc54d770p12040a5ca1492c50@mail.gmail.com> On Thu, Mar 11, 2010 at 10:12 PM, Howard Lovatt wrote: > All the implementations suggested to date require at least one new > object per lambda, so new is signaling that an object will in all > likely hood be created (unless the JVM can eliminate it). When a lambda expression captures no state from the enclosing scope, a single object can represent all evaluations of the same lambda expression, rather than requiring a new object for each evaluation of the lambda expression. This requires the specification NOT to require a distinct reference value for each evaluation of the lambda expression (which would conflict with "new"). In my experience, these use cases are more common than the use cases where a lambda is a closure. From john at milsson.nu Thu Mar 11 23:08:09 2010 From: john at milsson.nu (John Nilsson) Date: Fri, 12 Mar 2010 08:08:09 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> Message-ID: Key words being 'to date', if no specific implementation is dictated by the language spec why assume it will always be a bad one? BR, John On Fri, Mar 12, 2010 at 7:12 AM, Howard Lovatt wrote: > All the implementations suggested to date require at least one new > object per lambda, so new is signaling that an object will in all > likely hood be created (unless the JVM can eliminate it). > > On 12 March 2010 10:14, John Nilsson wrote: > > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt > > > wrote: > >> > >> There is an advantage in spelling out that you have an expensive > >> operation in that people are more likely to be aware of a potential > >> problem and hence avoid it in the first place > > > > > > But it is only expensive if you assume a broken compiler or VM. There is > > nothing inherent in the language to suggest that it should be expensive. > > BR, > > John > > > > -- > -- Howard. > From jjb at google.com Thu Mar 11 23:11:09 2010 From: jjb at google.com (Joshua Bloch) Date: Thu, 11 Mar 2010 23:11:09 -0800 Subject: A syntax option (function types versus arrays) In-Reply-To: <4B9967CE.7010306@the-loom.de> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> <4B9967CE.7010306@the-loom.de> Message-ID: <17b2302a1003112311p352f9965v39820eaa9636ec2b@mail.gmail.com> Stefan, Thanks, this is really useful! In my view, *all *of the Currying examples are rather ugly. Perhaps it isn't the syntax that's at fault, then. Perhaps the Currying itself is to blame, and ordinary Java programmers won't be writing this kind of code. If this is so, then I suppose we should be more concerned with the syntax of simpler examples. I think the currently proposed syntax (!) is pretty good for simple examples. Josh On Thu, Mar 11, 2010 at 1:59 PM, Stefan Schulz wrote: > On 11.03.2010 19:01, Joshua Bloch wrote: > > My two cents: > > > > #< #< R() throws E>( #< R( A ) throws E>, A )> curry = > > new #< #( #< R( A ) throws E> l, A a )>( l.( a ) ); > > > > (..) > > > > I do think it makes sense to explore new syntax proposals, but I'm not > sure > > I like this one better than the one that's currently on the table. > > Adding another two cents. The use of hash plus angle brackets plus round > parens gives quite some noise. I imagine adding some parameterized types > in such a definition ... > > I scanned the list and noted down the syntax proposals we have so far > (order of appearance on the list) using a simplyfied notation (ignoring > optional definitions). I also added a curry-example to each of them, > which I hopefully got right. > > Cheers, > Stefan > > > 1) Straw-man, latest > # ResultType ( TypeList ) ( throws ExceptionList ) > Curry-example: > ##R()(throws E) (#R(A)(throws E), A) curry = ... > > 2) Peter Levart, 26 Jan 2010 > # ( TypeList : ResultType throws ExceptionList ) > Curry-example: > #( #(A: R throws E), A: #(: R throws E) ) curry = ... > > 3) John Rose, 26 Jan 2010 ff > ( TypeList ) throws PipedExceptionList -> ResultType > Curry-example: > ((A) throws E -> R, A) -> () throws E -> R curry = ... > > 4) Neal Gafter, 27 Jan 2010 > # ( TypeList -> ResultType throws ExceptionList ) > Curry-example: > #(#(A -> R throws E), A) -> #( -> R throws E)) curry = ... > > 5) Stefan Schulz, 31 Jan 2010 > [ ResultType ( TypeList ) throws ExceptionList ] > Curry-example: > [[R() throws E]([R(A) throws E], A) curry = ... > > 6) Remi Forax, 09 Feb 2010 > TypeList throws ExceptionList -> ResultType > (plus additional parens rules) > Curry-Example: > (A throws E -> R), A -> (throws E -> R) curry = ... > > 7) Peter Levart, 9 Feb 2010 > ReturnType # ( TypeList ) throws ExceptionList > Curry-Example: > R #() throws E #(R #(A) throws E, A) curry = ... > > 8) Stefan Schulz, 16 Feb 2010 > (: TypeList -> ResultType throws ExceptionList ) > Curry-Example: > (: (: A -> R throws E ), A -> (: -> R throws E) ) curry = ... > > 9) Neal Gafter, 26 Feb 2010 > ( TypeList throws ExceptionList ) -> ResultType > Curry-Example: > ( (A throws E) -> R, A ) -> (throws E) -> R curry = ... > > 10) BGGA > { TypeList => ResultType throws ExceptionList } > Curry-example: > { {A => R throws E}, A => { => R throws E} } curry = ... > > 11) FCM > # ( ResultType ( TypeList ) throws ExceptionList ) > Curry-example: > #( #(R() throws E) ( #(R(A) throws E), A ) ) curry = ... > > 12) FCM Alternate > # ( TypeList return ResultType throws ExceptionList ) > Curry-example: > #( #(A return R throws E), A return #(return R throws E)) curry = ... > > 13) Howard Lovatt, 11 Mar 2010 > # < ResultType ( TypeList ) throws ExceptionList > > Curry-example: > #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = ... > > 14) Gernot Neppert, 11 Mar 2010 > lambda < ReturnType , TypeList , throws ExceptionList > > Curry-example: > lambda, lambda, A> curry = ... > > > From peter.levart at marand.si Thu Mar 11 23:40:49 2010 From: peter.levart at marand.si (Peter Levart) Date: Fri, 12 Mar 2010 08:40:49 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <3dd3f56a1003112216n4db0f491s6442b045397419d2@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> <3dd3f56a1003112216n4db0f491s6442b045397419d2@mail.gmail.com> Message-ID: <201003120840.49993.peter.levart@marand.si> On 03/12/10, Howard Lovatt wrote: > My understanding is that the JVM is free to optimize object creation > away as long as it can convince itself that the effect cannot be > observed, hence the escape analysis proposed that will stack allocate > instead of heap allocate. Escape analysis won't be able to optimize such "constant" lambda expressions in most cases where they should be optimized, since lambdas are there to be passed to some code (i.e. they escape compilation unit). On the other hand you usually won't need to depend on reference identity of a lambda instance, so it's perfectly understandable for specification to NOT specify it. Therefore "new" keyword is misleading in this respect. Regards, Peter > > On 12 March 2010 10:22, Alex Blewitt wrote: > > On 11 Mar 2010, at 23:14, John Nilsson wrote: > > > > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt > > wrote: > >> > >> There is an advantage in spelling out that you have an expensive > >> operation in that people are more likely to be aware of a potential > >> problem and hence avoid it in the first place > > > > > > But it is only expensive if you assume a broken compiler or VM. There is > > nothing inherent in the language to suggest that it should be expensive. > > > > If you specify 'new' then the runtime VM is forced to lay out space for the > > new data as well as return a fresh instance: > > http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#41147 > > Next, space is allocated for the new class instance. Every time the > > expression is evaluated, a fresh object is created > > So by using the keyword 'new' - and assuming unchanged semantics in this > > area of the JLS - then you are going to at least cycle through the new > > generation even if the runtime JIT may be able to optimise it away in > > certain circumstances. > > However, if the keyword 'new' is not used then these issues do not apply. > > Alex > > > > From Alex.Buckley at Sun.COM Fri Mar 12 04:18:41 2010 From: Alex.Buckley at Sun.COM (Alex Buckley) Date: Fri, 12 Mar 2010 04:18:41 -0800 Subject: Inverted syntax option In-Reply-To: References: Message-ID: <4B9A3121.3000700@sun.com> I would call these "naked lambdas" since the expression with # parameters is shorn of a signature or delimiters like {..}. But you still have to pay the cost of a static type system, by casting the positional parameters in order to do anything interesting with them. This seems like an original, but really quite painful, idea. Alex John Nilsson wrote: > Most syntax proposals so far has been variants of specifying the type and > arguments of the lambda to be created. I have another suggestion, inverted > lambdas. > > My suggestion is to focus on the current expression syntax of Java and just > tweak it a little bit to allow parameters. So any valid Java expression is a > lambda if it contains an identifier of the form # where denotes the > position in the argument list. > > Examples. (I have borrowed Neals type syntax, but my suggestion is just > about the expression syntax) > > (int,int) -> int adder = #1 + #2; > > int sum = intList.reduce(adder); > int sum2 = intList.reduce(#1 + #2); > > > When the type of an identifier is not known it defaults to Object > > Object expr = #1.method(); //Compiler error, method is not a member of > Object > Object expr2 = ((MyClass)#1).method(); //Typical cast already known to > Java-developers. > Object expr3 = ((MyClass)->Void) #1.method(); //This is also valid version > > > > BR, > John > From john at milsson.nu Fri Mar 12 11:31:08 2010 From: john at milsson.nu (John Nilsson) Date: Fri, 12 Mar 2010 20:31:08 +0100 Subject: Inverted syntax option In-Reply-To: <4B9A3121.3000700@sun.com> References: <4B9A3121.3000700@sun.com> Message-ID: On Fri, Mar 12, 2010 at 1:18 PM, Alex Buckley wrote: > I would call these "naked lambdas" since the expression with # > parameters is shorn of a signature or delimiters like {..}. But you > still have to pay the cost of a static type system, by casting the > positional parameters in order to do anything interesting with them. > This seems like an original, but really quite painful, idea. > Only if assigning to an Object reference. I imagine most uses of lambdas will be in arguments to methods where the argument type is specified. In these cases type inference should kick in and dictate the type. Given a method testThat(T t, (T)->bool pred){} a call like testThat(myObj, #1.aMethod() == null) would be legal. And the type of #1 would be inferred to be the same as myObj I do agree that naked lambdas is a better name though ;) BR, John From lk at teamten.com Fri Mar 12 12:02:17 2010 From: lk at teamten.com (Lawrence Kesteloot) Date: Fri, 12 Mar 2010 12:02:17 -0800 Subject: Inverted syntax option In-Reply-To: References: <4B9A3121.3000700@sun.com> Message-ID: <997cab101003121202q4de763dapceb7e34aeb9a5c12@mail.gmail.com> I think this approach is interesting, and perhaps some of the issues could be worked out with clever type inference, but IMO it's a deal breaker that it's not clear what the extent of the lambda expression is. If you write: foo(bar(baz(#1 + #2))); what is the lambda expression? It could be "#1 + #2" or "baz(#1 + #2)" or "bar(baz(#1 + #2))" and the compiler has to guess based on the parameters of these functions. The fact that it's not immediately obvious to the programmer what's being passed to what makes this a non-starter, as much as I like the nakedness of it. I also suspect you would eventually miss the named arguments, since they help document the code. Lawrence On Fri, Mar 12, 2010 at 11:31 AM, John Nilsson wrote: > On Fri, Mar 12, 2010 at 1:18 PM, Alex Buckley wrote: > >> I would call these "naked lambdas" since the expression with # >> parameters is shorn of a signature or delimiters like {..}. But you >> still have to pay the cost of a static type system, by casting the >> positional parameters in order to do anything interesting with them. >> This seems like an original, but really quite painful, idea. >> > Only if assigning to an Object reference. > > I imagine most uses of lambdas will be in arguments to methods where the > argument type is specified. In these cases type inference should kick in and > dictate the type. > > Given a method > testThat(T t, (T)->bool pred){} > > a call like > > testThat(myObj, #1.aMethod() == null) > > would be legal. And the type of #1 would be inferred to be the same as myObj > > I do agree that naked lambdas is a better name though ;) > > BR, > John > > From luc.duponcheel at gmail.com Fri Mar 12 12:18:16 2010 From: luc.duponcheel at gmail.com (Luc Duponcheel) Date: Fri, 12 Mar 2010 21:18:16 +0100 Subject: A syntax option (function types versus arrays) In-Reply-To: <17b2302a1003112311p352f9965v39820eaa9636ec2b@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <4B9927D7.9020407@sun.com> <17b2302a1003111001g4a45ac0ib36aaa80a1f575aa@mail.gmail.com> <4B9967CE.7010306@the-loom.de> <17b2302a1003112311p352f9965v39820eaa9636ec2b@mail.gmail.com> Message-ID: <1132700e1003121218j4d3fb34du5bfbfa92c9c5a464@mail.gmail.com> > Perhaps the Currying itself is to blame I'm not sure about this Josh Perhaps introducing Currying "as an afterthought" in Java is the real reason why all of the Currying examples look rather ugly Look at Scala: in principle code like while(condition){ code } could have been introduced into Scala at the library basis without extending the language *just because* while is a Curried function (and a few other things, like call-by-name) But, then again, Scala had Currying in the language "right from the start" Luc On Fri, Mar 12, 2010 at 8:11 AM, Joshua Bloch wrote: > Stefan, > > Thanks, this is really useful! > > In my view, *all *of the Currying examples are rather ugly. Perhaps it > isn't the syntax that's at fault, then. Perhaps the Currying itself is to > blame, and ordinary Java programmers won't be writing this kind of code. If > this is so, then I suppose we should be more concerned with the syntax of > simpler examples. I think the currently proposed syntax (!) is pretty good > for simple examples. > > Josh > > On Thu, Mar 11, 2010 at 1:59 PM, Stefan Schulz wrote: > > > On 11.03.2010 19:01, Joshua Bloch wrote: > > > My two cents: > > > > > > #< #< R() throws E>( #< R( A ) throws E>, A )> curry = > > > new #< #( #< R( A ) throws E> l, A a )>( l.( a ) > ); > > > > > > (..) > > > > > > I do think it makes sense to explore new syntax proposals, but I'm not > > sure > > > I like this one better than the one that's currently on the table. > > > > Adding another two cents. The use of hash plus angle brackets plus round > > parens gives quite some noise. I imagine adding some parameterized types > > in such a definition ... > > > > I scanned the list and noted down the syntax proposals we have so far > > (order of appearance on the list) using a simplyfied notation (ignoring > > optional definitions). I also added a curry-example to each of them, > > which I hopefully got right. > > > > Cheers, > > Stefan > > > > > > 1) Straw-man, latest > > # ResultType ( TypeList ) ( throws ExceptionList ) > > Curry-example: > > ##R()(throws E) (#R(A)(throws E), A) curry = ... > > > > 2) Peter Levart, 26 Jan 2010 > > # ( TypeList : ResultType throws ExceptionList ) > > Curry-example: > > #( #(A: R throws E), A: #(: R throws E) ) curry = ... > > > > 3) John Rose, 26 Jan 2010 ff > > ( TypeList ) throws PipedExceptionList -> ResultType > > Curry-example: > > ((A) throws E -> R, A) -> () throws E -> R curry = ... > > > > 4) Neal Gafter, 27 Jan 2010 > > # ( TypeList -> ResultType throws ExceptionList ) > > Curry-example: > > #(#(A -> R throws E), A) -> #( -> R throws E)) curry = ... > > > > 5) Stefan Schulz, 31 Jan 2010 > > [ ResultType ( TypeList ) throws ExceptionList ] > > Curry-example: > > [[R() throws E]([R(A) throws E], A) curry = ... > > > > 6) Remi Forax, 09 Feb 2010 > > TypeList throws ExceptionList -> ResultType > > (plus additional parens rules) > > Curry-Example: > > (A throws E -> R), A -> (throws E -> R) curry = ... > > > > 7) Peter Levart, 9 Feb 2010 > > ReturnType # ( TypeList ) throws ExceptionList > > Curry-Example: > > R #() throws E #(R #(A) throws E, A) curry = ... > > > > 8) Stefan Schulz, 16 Feb 2010 > > (: TypeList -> ResultType throws ExceptionList ) > > Curry-Example: > > (: (: A -> R throws E ), A -> (: -> R throws E) ) curry = ... > > > > 9) Neal Gafter, 26 Feb 2010 > > ( TypeList throws ExceptionList ) -> ResultType > > Curry-Example: > > ( (A throws E) -> R, A ) -> (throws E) -> R curry = ... > > > > 10) BGGA > > { TypeList => ResultType throws ExceptionList } > > Curry-example: > > { {A => R throws E}, A => { => R throws E} } curry = ... > > > > 11) FCM > > # ( ResultType ( TypeList ) throws ExceptionList ) > > Curry-example: > > #( #(R() throws E) ( #(R(A) throws E), A ) ) curry = ... > > > > 12) FCM Alternate > > # ( TypeList return ResultType throws ExceptionList ) > > Curry-example: > > #( #(A return R throws E), A return #(return R throws E)) curry = ... > > > > 13) Howard Lovatt, 11 Mar 2010 > > # < ResultType ( TypeList ) throws ExceptionList > > > Curry-example: > > #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = ... > > > > 14) Gernot Neppert, 11 Mar 2010 > > lambda < ReturnType , TypeList , throws ExceptionList > > > Curry-example: > > lambda, lambda, A> curry = ... > > > > > > > > -- __~O -\ <, (*)/ (*) reality goes far beyond imagination From bobfoster at gmail.com Fri Mar 12 12:49:21 2010 From: bobfoster at gmail.com (Bob Foster) Date: Fri, 12 Mar 2010 12:49:21 -0800 Subject: A syntax option (function types versus arrays) Message-ID: <47e7f7fd1003121249ic9353bai9f21dc1a1e5bbfe1@mail.gmail.com> Joshua Block wrote: >In my view, *all *of the Currying examples are rather ugly. Actually, Neil Gafter's is quite attractive. I would certainly have more than one date with it. > Perhaps the Currying itself is to > blame, and ordinary Java programmers won't be writing this kind of code. If > this is so, then I suppose we should be more concerned with the syntax of > simpler examples. Then drop curry, but don't go forward with a syntax that would allow one to find something like: ##R()(throws E) (#R(A)(throws E), A) curry = ... in a Java program. Your 'ordinary Java developer' may not write this, but they will be forced to read and maintain it. Beware of simple examples. > I think the currently proposed syntax (!) is pretty good > for simple examples. No, it's just pretty easy to parse. Otherwise, unlovely. Cheers! Bob From john at milsson.nu Fri Mar 12 12:50:23 2010 From: john at milsson.nu (John Nilsson) Date: Fri, 12 Mar 2010 21:50:23 +0100 Subject: Inverted syntax option In-Reply-To: <997cab101003121202q4de763dapceb7e34aeb9a5c12@mail.gmail.com> References: <4B9A3121.3000700@sun.com> <997cab101003121202q4de763dapceb7e34aeb9a5c12@mail.gmail.com> Message-ID: On Fri, Mar 12, 2010 at 9:02 PM, Lawrence Kesteloot wrote: > I think this approach is interesting, and perhaps some of the issues > could be worked out with clever type inference, but IMO it's a deal > breaker that it's not clear what the extent of the lambda expression > is. If you write: > > foo(bar(baz(#1 + #2))); > > what is the lambda expression? It could be "#1 + #2" or "baz(#1 + #2)" > or "bar(baz(#1 + #2))" and the compiler has to guess based on the > parameters of these functions. The fact that it's not immediately > obvious to the programmer what's being passed to what makes this a > non-starter, as much as I like the nakedness of it. Maybe it isn't so important. In some sense it shouldn't really matter, as long as it type checks. But it could be addressed with some optional delimiter: foo(bar(baz(#(#1 + #2))) I also suspect you > would eventually miss the named arguments, since they help document > the code. > This could be addressed with the previous proposals to support statements in expressions: (int a = #1; int b = #2; a+b) BR, John From howard.lovatt at gmail.com Fri Mar 12 15:49:59 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sat, 13 Mar 2010 10:49:59 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <201003120840.49993.peter.levart@marand.si> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <597A40BB-6D8D-416F-AC92-FD75CDC88818@gmail.com> <3dd3f56a1003112216n4db0f491s6442b045397419d2@mail.gmail.com> <201003120840.49993.peter.levart@marand.si> Message-ID: <3A63E097-6E1B-45C3-96B1-D766F5FCB519@gmail.com> I probably didn't make myself clear. I was not saying that escape analysis was the exclusive means or the most appropriate means of optimizing lambdas. I was simply pointing out that the JVM can and does optimize object creation. As to having the compiler do the optimization, this has proven to be troublsome because the compiler does not see the whole appplication (unlike the JVM). EG String caching and final field caching are full of gottchas. Therefore I think it is best left to the JVM. I agree that there are few uses for lambda identity. However there are some and it would also be confusing to have special rules for lambdas. Special rules are the cause of trouble for Stings and static finals. Best make everything an object with consistent rules. -- Howard Lovatt +61 419 971 263 (sent from my PDA) On 12/03/2010, at 6:40 PM, Peter Levart wrote: > On 03/12/10, Howard Lovatt wrote: >> My understanding is that the JVM is free to optimize object creation >> away as long as it can convince itself that the effect cannot be >> observed, hence the escape analysis proposed that will stack allocate >> instead of heap allocate. > > Escape analysis won't be able to optimize such "constant" lambda > expressions in most cases where they should be optimized, since > lambdas are there to be passed to some code (i.e. they escape > compilation unit). On the other hand you usually won't need to > depend on reference identity of a lambda instance, so it's perfectly > understandable for specification to NOT specify it. Therefore "new" > keyword is misleading in this respect. > > Regards, Peter > >> >> On 12 March 2010 10:22, Alex Blewitt wrote: >>> On 11 Mar 2010, at 23:14, John Nilsson wrote: >>> >>> On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt >> > >>> wrote: >>>> >>>> There is an advantage in spelling out that you have an expensive >>>> operation in that people are more likely to be aware of a potential >>>> problem and hence avoid it in the first place >>> >>> >>> But it is only expensive if you assume a broken compiler or VM. >>> There is >>> nothing inherent in the language to suggest that it should be >>> expensive. >>> >>> If you specify 'new' then the runtime VM is forced to lay out >>> space for the >>> new data as well as return a fresh instance: >>> http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#41147 >>> Next, space is allocated for the new class instance. Every time the >>> expression is evaluated, a fresh object is created >>> So by using the keyword 'new' - and assuming unchanged semantics >>> in this >>> area of the JLS - then you are going to at least cycle through the >>> new >>> generation even if the runtime JIT may be able to optimise it away >>> in >>> certain circumstances. >>> However, if the keyword 'new' is not used then these issues do >>> not apply. >>> Alex >> >> >> >> From howard.lovatt at gmail.com Fri Mar 12 15:55:09 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sat, 13 Mar 2010 10:55:09 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> Message-ID: <71AA4463-4B67-44BE-B407-DBEC11CE315D@gmail.com> I wasn't implying that the JVM couldn't optimize away the object creation -- Howard Lovatt +61 419 971 263 (sent from my PDA) On 12/03/2010, at 6:08 PM, John Nilsson wrote: > Key words being 'to date', if no specific implementation is dictated > by the language spec why assume it will always be a bad one? > > BR, > John > > On Fri, Mar 12, 2010 at 7:12 AM, Howard Lovatt > wrote: > All the implementations suggested to date require at least one new > object per lambda, so new is signaling that an object will in all > likely hood be created (unless the JVM can eliminate it). > > On 12 March 2010 10:14, John Nilsson wrote: > > On Thu, Mar 11, 2010 at 11:58 PM, Howard Lovatt > > > wrote: > >> > >> There is an advantage in spelling out that you have an expensive > >> operation in that people are more likely to be aware of a potential > >> problem and hence avoid it in the first place > > > > > > But it is only expensive if you assume a broken compiler or VM. > There is > > nothing inherent in the language to suggest that it should be > expensive. > > BR, > > John > > > > -- > -- Howard. > From howard.lovatt at gmail.com Fri Mar 12 15:56:22 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sat, 13 Mar 2010 10:56:22 +1100 Subject: A syntax option (function types versus arrays) In-Reply-To: <15e8b9d21003112254lc54d770p12040a5ca1492c50@mail.gmail.com> References: <3dd3f56a1003102208m12bd1508ma95b3e91a588251d@mail.gmail.com> <1f5b87141003102350j2549a1e2n57cd7cd63e6eb97e@mail.gmail.com> <3dd3f56a1003111458t1cadf9aex2c00db9a09fd22be@mail.gmail.com> <3dd3f56a1003112212p7709bb5bu84c6c78887719e6c@mail.gmail.com> <15e8b9d21003112254lc54d770p12040a5ca1492c50@mail.gmail.com> Message-ID: <04871086-D097-45D8-A27B-2B242C9DC86E@gmail.com> Sure, nothing to stop the JVM doing this -- Howard Lovatt +61 419 971 263 (sent from my PDA) On 12/03/2010, at 5:54 PM, Neal Gafter wrote: > On Thu, Mar 11, 2010 at 10:12 PM, Howard Lovatt > wrote: >> All the implementations suggested to date require at least one new >> object per lambda, so new is signaling that an object will in all >> likely hood be created (unless the JVM can eliminate it). > > When a lambda expression captures no state from the enclosing scope, a > single object can represent all evaluations of the same lambda > expression, rather than requiring a new object for each evaluation of > the lambda expression. This requires the specification NOT to require > a distinct reference value for each evaluation of the lambda > expression (which would conflict with "new"). In my experience, these > use cases are more common than the use cases where a lambda is a > closure. From scolebourne at joda.org Sun Mar 14 06:21:22 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Sun, 14 Mar 2010 13:21:22 +0000 Subject: C++11 lambdas Message-ID: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> Apparently the C++0x specification is moving into a final stage (and to be known as C++11) http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ As C++ is similar to Java, I though it was worth having a look at what the lambda specification is that they are planning to add (http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3035.pdf section 5.1.2) The basic lambda function is: [](int x, int y) -> int { int z = x + y; return z + x; } where the (int x, int y) are the arguments (optional if no arguments), -> int is the return type (optional, can be inferred), and the {} is the block. I note the use of local-return and round bracket parameters. The square brackets are used to access local variables: int total = 0; list.each( [&total](int x) { total += x; } ); Where &total "enables" the local variable to be seen and used (local variables are not accessible by default). This technique creates a closure. If the square brackets contain [&] then all local variables are closed over and made available. By comparison, if the variable name is used without the & prefix, then the variable is copied (not closed over). [=] copies all variables in scope. [&] - closes over all local variables including "this" [&total] - closes over just the total variable [=] - copies all local variables on construction including "this" [total] - copies the total local variable on construction [&total, value] - closes over total and copies value [this] - copies reference to "this" The "this" keyword does NOT appear to refer to the lambda. There appear to be no function types. Of course, if I've got something wrong, please correct! So, wrt to Project Lambda same: - local "return" - round bracket arguments - curly brace blocks - introducing symbol (# or []) different: - no local "this" - optional round bracket arguments (when no args) - optional return type - import of local variables by reference or copy (controlled by programmer) - no function types I make no comment here on the up or down side of each of these differences. Stephen From neal at gafter.com Sun Mar 14 07:31:15 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 14 Mar 2010 06:31:15 -0800 Subject: C++11 lambdas In-Reply-To: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> Message-ID: <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> On Sun, Mar 14, 2010 at 5:21 AM, Stephen Colebourne wrote: > - no function types > Correction: C++ has had function types all along. so it hasn't been necessary to add them. They are invariant. From forax at univ-mlv.fr Sun Mar 14 09:14:29 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sun, 14 Mar 2010 17:14:29 +0100 Subject: C++11 lambdas In-Reply-To: <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> Message-ID: <4B9D0B65.6060508@univ-mlv.fr> Le 14/03/2010 15:31, Neal Gafter a ?crit : > On Sun, Mar 14, 2010 at 5:21 AM, Stephen Colebournewrote: > > >> - no function types >> >> > Correction: C++ has had function types all along. so it hasn't been > necessary to add them. They are invariant. > > Yes, seeing that I wonder if we are not going in the wrong direction by trying to protect lambda and function type by a # or some enclosing parens. Why not trying something simpler ? A function that takes an int and returns an int: int(int) A function that takes an int and returns nothing: void(int) A function that takes two ints and returns an int: int(int, int) A function that throws an Exception: int(int) throws Exception A function that takes a function that throws an Exception: int(int(int) throws Exception) A function that throws an Exception and takes a function int(int(int)) throws Exception A function that takes an int and returns a function that returns an int int() (int) curry! R() throws E (R(A) throws E, A) curry = ... Grammar: ResultType ( TypeList ) throws ExceptionList And removing the # in the lambda syntax: int(int) fun = (int x) (x); // lambda expression int(int) fun = (int x) { return x; }; // lambda block A method that returns a lambda: int(int,int) plus() { return (int x, int y) (x+y); } A method that takes two function types and returns a lambda: int(int,int) filter(int(int) filter, int(int,int) operation) { return (int x, int y) { return operation.(filter.(x), filter.(y)); }; } R?mi From scolebourne at joda.org Sun Mar 14 10:56:20 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Sun, 14 Mar 2010 17:56:20 +0000 Subject: Summary: Function type syntax Message-ID: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> (Extracting Stefan's list and enhancing) 1) Straw-man, latest # ResultType ( TypeList ) ( throws ExceptionList ) #int() #String(File)(throws IOException) ##R()(throws E) (#R(A)(throws E), A) curry = ... 2) Peter Levart, 26 Jan 2010 # ( TypeList : ResultType throws ExceptionList ) #(:int) #(File:String throws IOException) #( #(A: R throws E), A: #(: R throws E) ) curry = ... 3) John Rose, 26 Jan 2010 ff ( TypeList ) throws PipedExceptionList -> ResultType () -> int (File throws IOException) -> String ((A) throws E -> R, A) -> () throws E -> R curry = ... 4) Neal Gafter, 27 Jan 2010 # ( TypeList -> ResultType throws ExceptionList ) #(->int) #(File -> String throws IOException) #(#(A -> R throws E), A) -> #( -> R throws E)) curry = ... 5) Stefan Schulz, 31 Jan 2010 [ ResultType ( TypeList ) throws ExceptionList ] [int()] [String(File) throws IOException] [[R() throws E]([R(A) throws E], A) curry = ... 6) Remi Forax, 09 Feb 2010 TypeList throws ExceptionList -> ResultType (plus additional parens rules) (->int) (File throws IOException -> String) (A throws E -> R), A -> (throws E -> R) curry = ... 7) Peter Levart, 9 Feb 2010 ReturnType # ( TypeList ) throws ExceptionList int#() String#(File) IOException R #() throws E #(R #(A) throws E, A) curry = ... 8) Stefan Schulz, 16 Feb 2010 (: TypeList -> ResultType throws ExceptionList ) (: -> int) (: File -> String throws IOException) (: (: A -> R throws E ), A -> (: -> R throws E) ) curry = ... 9) Neal Gafter, 26 Feb 2010 ( TypeList throws ExceptionList ) -> ResultType () -> int (File throws IOException) -> String ( (A throws E) -> R, A ) -> (throws E) -> R curry = ... 10) BGGA { TypeList => ResultType throws ExceptionList } { => int} ( File => String throws IOException} { {A => R throws E}, A => { => R throws E} } curry = ... 11) FCM # ( ResultType ( TypeList ) throws ExceptionList ) #int() #String(File) throws IOException #( #(R() throws E) ( #(R(A) throws E), A ) ) curry = ... 12) FCM Alternate # ( TypeList return ResultType throws ExceptionList ) #(return int) #(File return int throws IOException) #( #(A return R throws E), A return #(return R throws E)) curry = ... 13) Howard Lovatt, 11 Mar 2010 # < ResultType ( TypeList ) throws ExceptionList > # # #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = ... 14) Gernot Neppert, 11 Mar 2010 lambda < ReturnType , TypeList , throws ExceptionList > lambda lambda lambda, lambda, A> curry = ... 15) Lightweight interfaces, 19 Feb 2010 interface Name ReturnType ( TypeList ) throws ExceptionList; interface Counter int(); interface Reader String(File) throws IOException; interface CurryBase R(A) throws E interface CurryResult R() throws E interface Curry CurryResult( CurryBase, A ) Hope this helps, Stephen From jp at hapra.at Sun Mar 14 11:02:40 2010 From: jp at hapra.at (Jakob Praher) Date: Sun, 14 Mar 2010 19:02:40 +0100 Subject: C++11 lambdas In-Reply-To: <4B9D0B65.6060508@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> Message-ID: <4B9D24C0.6070207@hapra.at> Dear R?mi, I argumented this on the closures-dev list in similar ways: * http://mail.openjdk.java.net/pipermail/closures-dev/2009-November/000278.html * http://mail.openjdk.java.net/pipermail/closures-dev/2009-November/000281.html Yet I like your idea of lambdas and I also mentioned that D allows for similar construct [1] (see the third alternative for FuncionLiteral): FunctionLiteral: function Typeopt ParameterAttributes opt FunctionBody delegate Typeopt ParameterAttributes opt FunctionBody ParameterAttributes FunctionBody FunctionBody ParameterAttributes: Parameters Parameters FunctionAttributes So from myside: I like the idea! -- Jakob Am 14.03.10 17:14, schrieb R?mi Forax: > > Yes, seeing that I wonder if we are not going in the wrong direction by > trying > to protect lambda and function type by a # or some enclosing parens. > > Why not trying something simpler ? > > > A function that takes an int and returns an int: > int(int) > > A function that takes an int and returns nothing: > void(int) > > A function that takes two ints and returns an int: > int(int, int) > > A function that throws an Exception: > int(int) throws Exception > > A function that takes a function that throws an Exception: > int(int(int) throws Exception) > > A function that throws an Exception and takes a function > int(int(int)) throws Exception > > A function that takes an int and returns a function that returns an int > int() (int) > > curry! > R() throws E (R(A) throws E, A) curry = ... > > Grammar: > ResultType ( TypeList ) throws ExceptionList > > > And removing the # in the lambda syntax: > > int(int) fun = (int x) (x); // lambda expression > int(int) fun = (int x) { return x; }; // lambda block > > A method that returns a lambda: > int(int,int) plus() { > return (int x, int y) (x+y); > } > > A method that takes two function types and returns a lambda: > int(int,int) filter(int(int) filter, int(int,int) operation) { > return (int x, int y) { > return operation.(filter.(x), filter.(y)); > }; > } > > > R?mi > > > From pbenedict at apache.org Sun Mar 14 12:35:33 2010 From: pbenedict at apache.org (Paul Benedict) Date: Sun, 14 Mar 2010 14:35:33 -0500 Subject: C++11 lambdas In-Reply-To: <4B9D0B65.6060508@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> Message-ID: I wholly agree with Remi. The current lamda discussions have created virtually unreadable syntax -- I practically felt buried by the parade of syntax tokens! Going back to simple types that look like C function pointers is so much better than what is being discussed now. I think "the wrong direction" was aptly put. On Sun, Mar 14, 2010 at 11:14 AM, R?mi Forax wrote: > Le 14/03/2010 15:31, Neal Gafter a ?crit : >> On Sun, Mar 14, 2010 at 5:21 AM, Stephen Colebournewrote: > Yes, seeing that I wonder if we are not going in the wrong direction by > trying > to protect lambda and function type by a # or some enclosing parens. > > Why not trying something simpler ? > > > A function that takes an int and returns an int: > int(int) > > A function that takes an int and returns nothing: > void(int) > > A function that takes two ints and returns an int: > int(int, int) > > A function that throws an Exception: > int(int) throws Exception > > A function that takes a function that throws an Exception: > int(int(int) throws Exception) > > A function that throws an Exception and takes a function > int(int(int)) throws Exception > > A function that takes an int and returns a function that returns an int > int() (int) > > curry! > R() throws E (R(A) throws E, A) curry = ... > > Grammar: > ResultType ( TypeList ) throws ExceptionList > > > And removing the # in the lambda syntax: > > int(int) fun = (int x) (x); ?// lambda expression > int(int) fun = (int x) { return x; }; ?// lambda block > > A method that returns a lambda: > int(int,int) plus() { > ? return (int x, int y) (x+y); > } > > A method that takes two function types and returns a lambda: > int(int,int) filter(int(int) filter, int(int,int) operation) { > ? return (int x, int y) { > ? ? return operation.(filter.(x), filter.(y)); > ? }; > } From howard.lovatt at gmail.com Sun Mar 14 13:03:48 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 15 Mar 2010 07:03:48 +1100 Subject: Summary: Function type syntax Message-ID: <959E0DA0-F5BA-49AB-A455-8DB7F3BA4F42@gmail.com> Great list. Could you add an array example to each option? -- Howard Lovatt +61 419 971 263 (sent from my PDA) From schulz at the-loom.de Sun Mar 14 13:25:27 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Sun, 14 Mar 2010 21:25:27 +0100 Subject: C++11 lambdas In-Reply-To: <4B9D0B65.6060508@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> Message-ID: <4B9D4637.3050500@the-loom.de> Am 14.03.2010 17:14, schrieb R?mi Forax: > A function that takes an int and returns an int: > int(int) If "call" is a parameterless method as well as the name of a class in scope, what would the following resolve to: call() > curry! > R() throws E (R(A) throws E, A) curry = ... How are multiple exceptions to be defined for the throws clause? Using a pipe? Using parens? Stefan From Thomas.Hawtin at Sun.COM Sun Mar 14 13:40:04 2010 From: Thomas.Hawtin at Sun.COM (Tom Hawtin) Date: Sun, 14 Mar 2010 20:40:04 +0000 Subject: Summary: Function type syntax In-Reply-To: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> Message-ID: <4B9D49A4.4040501@sun.com> Stephen Colebourne wrote: > (Extracting Stefan's list and enhancing) > > [...] > 15) Lightweight interfaces, 19 Feb 2010 > interface Name ReturnType ( TypeList ) throws ExceptionList; > interface Counter int(); Oh, it's a counter. I got this far and I didn't know what it was supposed to be. > interface Reader String(File) throws IOException; Not a display name for the file then? > interface CurryBase R(A) throws E ^A ^; ? > interface CurryResult R() throws E > interface Curry CurryResult( CurryBase, A ) ^, I'm not sure the curry example is that useful. The idea is to use meaningful types? But at least it is understandable, with some effort. I don't understand the allergy to names. It would be nice to be able to refer to the arguments. Put in names, and there is no need to add to the method call syntax. For comparison, here's how it is in existing Java with just "throws" added: interface Name { ReturnType MethodId ( FormalParameterDecls ) throws ExceptionList; } interface Counter { int next(); } interface Reader { String read(File file) throws IOException; } interface CurryOp { R op(A arg) throws E; } interface CurryCall { R call() throws E; } interface Curry { CurryOp apply(CurryCall op, A arg); } That's not so bad declaration side. Tom From forax at univ-mlv.fr Sun Mar 14 14:00:54 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sun, 14 Mar 2010 22:00:54 +0100 Subject: C++11 lambdas In-Reply-To: <4B9D4637.3050500@the-loom.de> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <4B9D4637.3050500@the-loom.de> Message-ID: <4B9D4E86.40906@univ-mlv.fr> Le 14/03/2010 21:25, Stefan Schulz a ?crit : > Am 14.03.2010 17:14, schrieb R?mi Forax: > >> A function that takes an int and returns an int: >> int(int) >> > If "call" is a parameterless method as well as the name of a class in > scope, what would the following resolve to: > call() > Perhaps I'm wrong but the context after "call()" seem sufficient to disambiguate. call() a; // a declaration call(); // a method call > >> curry! >> R() throws E (R(A) throws E, A) curry = ... >> > How are multiple exceptions to be defined for the throws clause? Using a > pipe? Using parens? > I would prefer pipe, generics syntax already use & for a similar problem. > Stefan > R?mi From schulz at the-loom.de Mon Mar 15 00:18:05 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Mon, 15 Mar 2010 08:18:05 +0100 Subject: C++11 lambdas In-Reply-To: <4B9D4E86.40906@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <4B9D4637.3050500@the-loom.de> <4B9D4E86.40906@univ-mlv.fr> Message-ID: <4B9DDF2D.3090800@the-loom.de> Am 14.03.2010 22:00, schrieb R?mi Forax: > Perhaps I'm wrong but the context after "call()" > seem sufficient to disambiguate. > > call() a; // a declaration > call(); // a method call You are right, I was thinking out of context... I just find it to be not very visible (which might be fine, though). Object() (a); // an expression lambda Object() a; // a function type declaration Object() {Object a = create(); return a;}; // a block lambda new Object() {Object a = create();}; // an anonymous class Stefan From forax at univ-mlv.fr Mon Mar 15 04:01:45 2010 From: forax at univ-mlv.fr (=?ISO-8859-15?Q?R=E9mi_Forax?=) Date: Mon, 15 Mar 2010 12:01:45 +0100 Subject: C++11 lambdas In-Reply-To: <4B9DDF2D.3090800@the-loom.de> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <4B9D4637.3050500@the-loom.de> <4B9D4E86.40906@univ-mlv.fr> <4B9DDF2D.3090800@the-loom.de> Message-ID: <4B9E1399.2040001@univ-mlv.fr> Le 15/03/2010 08:18, Stefan Schulz a ?crit : > Am 14.03.2010 22:00, schrieb R?mi Forax: > >> Perhaps I'm wrong but the context after "call()" >> seem sufficient to disambiguate. >> >> call() a; // a declaration >> call(); // a method call >> > You are right, I was thinking out of context... I just find it to be not > very visible (which might be fine, though). > > Object() (a); // an expression lambda > Object() a; // a function type declaration > Object() {Object a = create(); return a;}; // a block lambda > new Object() {Object a = create();}; // an anonymous class > > Stefan > Stefan, like 3; is not a valid instruction in Java, Object() (a); and Object() {Object a = create(); return a;}; should not compile because they are expression without side effect. R?mi From schulz at the-loom.de Mon Mar 15 04:17:47 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Mon, 15 Mar 2010 12:17:47 +0100 Subject: C++11 lambdas In-Reply-To: <4B9E1399.2040001@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <4B9D4637.3050500@the-loom.de> <4B9D4E86.40906@univ-mlv.fr> <4B9DDF2D.3090800@the-loom.de> <4B9E1399.2040001@univ-mlv.fr> Message-ID: <4B9E175B.9000806@the-loom.de> Am 15.03.2010 12:01, schrieb R?mi Forax: > Le 15/03/2010 08:18, Stefan Schulz a ?crit : >> Object() (a); // an expression lambda >> Object() a; // a function type declaration >> Object() {Object a = create(); return a;}; // a block lambda >> new Object() {Object a = create();}; // an anonymous class > > like 3; is not a valid instruction in Java, > Object() (a); and Object() {Object a = create(); return a;}; > should not compile because they are expression without side effect. I left out assignments of the statements/expressions, as it could simply be an "Object o = " in all cases (except function type declaration), if that is what you meant with side effect. I just wanted to show how similar they look in syntax, I'm not implying any judgement on whether that is positive or negative. Stefan From bobfoster at gmail.com Mon Mar 15 12:09:22 2010 From: bobfoster at gmail.com (Bob Foster) Date: Mon, 15 Mar 2010 12:09:22 -0700 Subject: Inverted syntax option Message-ID: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> John Nilsson wrote: > On Fri, Mar 12, 2010 at 9:02 PM, Lawrence Kesteloot wrote: >> ...If you write: >> foo(bar(baz(#1 + #2))); >> what is the lambda expression? It could be "#1 + #2" or "baz(#1 + #2)" >> or "bar(baz(#1 + #2))" and the compiler has to guess based on the >> parameters of these functions. The fact that it's not immediately >> obvious to the programmer what's being passed to what makes this a >> non-starter, as much as I like the nakedness of it. > > Maybe it isn't so important. In some sense it shouldn't really matter, as > long as it type checks. > But it could be addressed with some optional delimiter: > > foo(bar(baz(#(#1 + #2))) > >> ...I also suspect you >> would eventually miss the named arguments, since they help document >> the code. > > This could be addressed with the previous proposals to support statements in > expressions: > > (int a = #1; int b = #2; a+b) Perhaps you meant this to illustrate how awkward and regressive this numbered-argument syntax is, and if so I applaud you for the examples. If this is a serious proposal, I suggest swapping the % character for # (the parser can figure it out by its prefix operator position) so everyone will understand that the new model for the Java language is the MS-DOS command line. baz(%1 + %2) Bob From reinier at zwitserloot.com Mon Mar 15 13:09:25 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 15 Mar 2010 21:09:25 +0100 Subject: Inverted syntax option In-Reply-To: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> References: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> Message-ID: <560fb5ed1003151309u59fe8fd3i387258f38e084a9e@mail.gmail.com> It's an interesting idea, but as Lawrence showed, without a delimiter resolution is complicated. I can't speak for the people who decide in the end, but I'd eat my shoes if significant additional complexity in the resolution process is acceptable. Method resolution is already a complex beast that's got a lot of words dedicated to it in the JLS and is already a fine source of puzzlers and a hefty retarding force for future language improvements. Piling on more complexity is therefore out of the question, most likely. Thus, when you have no delimiters the resolution algorithm would have to be 'trivial'. Which is kind of hard to see. For example, this seems trivial: #1 + #2 but it actually isn't. This looks like a single closure that adds argument number 1 and argument number 2 together, but it doesn't _have_ to be. It could also be two closures, the first one simply returning its first argument, the second simply returning its second, which are added together. Aside from having trouble even delimiting this notion, it also raises the question: How many arguments are there (just because #3 isn't mentioned doesn't technically mean it couldn't exist; plenty of times where you have a method that takes an argument that your implementation ends up not using, just so your method fits a certain interface), and what are their types? I can only conclude that this idea is simply not going to work as written. It might well work in a dynamic typing system where you don't need to know the types of the arguments, but java's typing system doesn't work that way. What COULD work is an offshoot that looks something like this: #(int, int) (#1 + #2) in other words, remove the names of parameters, preferring numeric access instead. This has the benefit of producing code that's smaller, but, I doubt its worth the significant cost in doing it: #1 and #2 don't look anything like any existing java concept, whereas naming the parameters does (it looks like method parameters), in non-tiny closures the numbers are going to get confusing (for obvious reasons; a number conveys less information than a name. There's a reason we don't advocate naming your variables "a", "b", "c", after all), and now the closure's signature is hard to distinguish from a function type. Of course, if function types went away in favour of always fitting the closure to an appropriate SAM type, that distinguishing problem also goes away, but you still have to contend with the unfamiliarity and lack of clarity, all to get only a very tiny gain in terseness. --Reinier Zwitserloot On Mon, Mar 15, 2010 at 8:09 PM, Bob Foster wrote: > John Nilsson wrote: > > On Fri, Mar 12, 2010 at 9:02 PM, Lawrence Kesteloot > wrote: > >> ...If you write: > >> foo(bar(baz(#1 + #2))); > >> what is the lambda expression? It could be "#1 + #2" or "baz(#1 + #2)" > >> or "bar(baz(#1 + #2))" and the compiler has to guess based on the > >> parameters of these functions. The fact that it's not immediately > >> obvious to the programmer what's being passed to what makes this a > >> non-starter, as much as I like the nakedness of it. > > > > Maybe it isn't so important. In some sense it shouldn't really matter, as > > long as it type checks. > > But it could be addressed with some optional delimiter: > > > > foo(bar(baz(#(#1 + #2))) > > > >> ...I also suspect you > >> would eventually miss the named arguments, since they help document > >> the code. > > > > This could be addressed with the previous proposals to support statements > in > > expressions: > > > > (int a = #1; int b = #2; a+b) > > Perhaps you meant this to illustrate how awkward and regressive this > numbered-argument syntax is, and if so I applaud you for the examples. > > If this is a serious proposal, I suggest swapping the % character for # > (the > parser can figure it out by its prefix operator position) so everyone will > understand that the new model for the Java language is the MS-DOS command > line. > > baz(%1 + %2) > > Bob > > From reinier at zwitserloot.com Mon Mar 15 13:33:15 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 15 Mar 2010 21:33:15 +0100 Subject: C++11 lambdas In-Reply-To: <4B9D0B65.6060508@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> Message-ID: <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> Once you add enough delimiters to eliminate all ambiguity in this syntax, Remi, you'll arrive pretty much at the closure proposal that's the status quo right now. For example, your syntax cannot differentiate between multiple exceptions and a listing of types: void(int() throws Exception1, Exception2) Is this: A) a function type that returns nothing and takes 1 parameter: int() throws Exception1, Exception2 B) a function type that returns nothing and takes 2 parameters: int() throws Exception1, as well as parameter of type Exception2? Second example: int(); Is this: A) A syntax error: A function type representing a return type of int with no arguments, by itself and thus invalid? B) A syntax error: The invocation of a method named 'int', which is not valid because 'int' is a reserved keyword? What error should the compiler generate? Can you tell what was intended? Vague error messages or error messages that don't do a good job of explaining what you did wrong is something that java doesn't have that much trouble with compared to for example Scala. It's a significant cost to bear if this means the compiler starts generating confusing, vacuous, or downright wrong error messages. I wrote down a few more examples, and anytime I made even a single change to some syntax, the meaning became _completely_ different. A far too heavy price, in my opinion. I actually like the # as a clear visual signal that there's a closure definition around. --Reinier Zwitserloot On Sun, Mar 14, 2010 at 5:14 PM, R?mi Forax wrote: > Le 14/03/2010 15:31, Neal Gafter a ?crit : > > On Sun, Mar 14, 2010 at 5:21 AM, Stephen Colebourne >wrote: > > > > > >> - no function types > >> > >> > > Correction: C++ has had function types all along. so it hasn't been > > necessary to add them. They are invariant. > > > > > > Yes, seeing that I wonder if we are not going in the wrong direction by > trying > to protect lambda and function type by a # or some enclosing parens. > > Why not trying something simpler ? > > > A function that takes an int and returns an int: > int(int) > > A function that takes an int and returns nothing: > void(int) > > A function that takes two ints and returns an int: > int(int, int) > > A function that throws an Exception: > int(int) throws Exception > > A function that takes a function that throws an Exception: > int(int(int) throws Exception) > > A function that throws an Exception and takes a function > int(int(int)) throws Exception > > A function that takes an int and returns a function that returns an int > int() (int) > > curry! > R() throws E (R(A) throws E, A) curry = ... > > Grammar: > ResultType ( TypeList ) throws ExceptionList > > > And removing the # in the lambda syntax: > > int(int) fun = (int x) (x); // lambda expression > int(int) fun = (int x) { return x; }; // lambda block > > A method that returns a lambda: > int(int,int) plus() { > return (int x, int y) (x+y); > } > > A method that takes two function types and returns a lambda: > int(int,int) filter(int(int) filter, int(int,int) operation) { > return (int x, int y) { > return operation.(filter.(x), filter.(y)); > }; > } > > > R?mi > > From john at milsson.nu Mon Mar 15 14:56:16 2010 From: john at milsson.nu (John Nilsson) Date: Mon, 15 Mar 2010 22:56:16 +0100 Subject: Inverted syntax option In-Reply-To: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> References: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> Message-ID: On Mon, Mar 15, 2010 at 8:09 PM, Bob Foster wrote: > Perhaps you meant this to illustrate how awkward and regressive this > numbered-argument syntax is, and if so I applaud you for the examples. > > If this is a serious proposal, I suggest swapping the % character for # > (the parser can figure it out by its prefix operator position) so everyone > will understand that the new model for the Java language is the MS-DOS > command line. > > baz(%1 + %2) > ;-) I was actually thinking of $1 + $2 (Bash style) but $ is already a valid identifier as far as I know... But yes it was intended as a serious proposal. If the alternative is some monstrosity such as new lambda(int a, int b) { return a + b: } to express a simple concept that shouldn't require more characters than one to be perfectly clear: + I'm quite found of the Scala approach to lambdas where syntax is mostly optional when the context can be used to infer the intended lambda. #1 + #2 is kind of compromise in that regard as it has been my impression that the Java crowd here isn't to found of terseness. BR, John From forax at univ-mlv.fr Mon Mar 15 15:08:14 2010 From: forax at univ-mlv.fr (=?UTF-8?B?UsOpbWkgRm9yYXg=?=) Date: Mon, 15 Mar 2010 23:08:14 +0100 Subject: C++11 lambdas In-Reply-To: <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> Message-ID: <4B9EAFCE.1010305@univ-mlv.fr> Le 15/03/2010 21:33, Reinier Zwitserloot a ?crit : > Once you add enough delimiters to eliminate all ambiguity in this > syntax, Remi, you'll arrive pretty much at the closure proposal that's > the status quo right now. I don't think so :) > > For example, your syntax cannot differentiate between multiple > exceptions and a listing of types: > > void(int() throws Exception1, Exception2) > > Is this: > > A) a function type that returns nothing and takes 1 parameter: int() > throws Exception1, Exception2 > > B) a function type that returns nothing and takes 2 parameters: int() > throws Exception1, as well as parameter of type Exception2? Exceptions are separated by pipes. > > Second example: > > > int(); > > Is this: > > A) A syntax error: A function type representing a return type of int > with no arguments, by itself and thus invalid? > > B) A syntax error: The invocation of a method named 'int', which is > not valid because 'int' is a reserved keyword? > > > What error should the compiler generate? Can you tell what was > intended? Vague error messages or error messages that don't do a good > job of explaining what you did wrong is something that java doesn't > have that much trouble with compared to for example Scala. It's a > significant cost to bear if this means the compiler starts generating > confusing, vacuous, or downright wrong error messages. I don't follow you. What is the error the compiler should output ? > > > > I wrote down a few more examples, and anytime I made even a single > change to some syntax, the meaning became _completely_ different. A > far too heavy price, in my opinion. I actually like the # as a clear > visual signal that there's a closure definition around. You can also see # as a visual clutter. > > --Reinier Zwitserloot R?mi From reinier at zwitserloot.com Mon Mar 15 15:11:20 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 15 Mar 2010 23:11:20 +0100 Subject: C++11 lambdas In-Reply-To: <4B9EAFCE.1010305@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> <4B9EAFCE.1010305@univ-mlv.fr> Message-ID: <560fb5ed1003151511p8c4b227h9169303c2b50e5a0@mail.gmail.com> On Mon, Mar 15, 2010 at 11:08 PM, R?mi Forax wrote: > I don't follow you. > What is the error the compiler should output ? > > Exactly. It's not clear anymore. Hence the compiler can choose to either emit one error, which means it generates something very confusing in 50% of the cases, or, it can choose to emit a rambling error that lists all the possible causes. That was the point: This is a bad thing. With the # the intent is more clear, which leads to better error messaging. As far as the compiler is concerned, no #, no closure. The same thing happens right now in for example class declarations. If you don't include a class declaration indicator ('class', 'interface', or 'enum') both ecj and javac do not consider it a (botched) type declaration. > > You can also see # as a visual clutter. > > Given that closures aren't in java today, and given that the way closures are going, what with the function types, it's not going to be completely integrated into all existing java code, probably _ever_, the notion that closures are as common as, let's say, int literals, doesn't sound right. Therefore, no, it's not visual clutter. Either way, with the 'visual clutter', the compiler will continue to emit sensible error messages. Without it, a sizable set of commonly emitted error messages are going to lose clarifying power, due to the extreme similarities between closure declarations, function type references, and existing legal java code constructs. From john at milsson.nu Mon Mar 15 15:20:48 2010 From: john at milsson.nu (John Nilsson) Date: Mon, 15 Mar 2010 23:20:48 +0100 Subject: Inverted syntax option In-Reply-To: <560fb5ed1003151309u59fe8fd3i387258f38e084a9e@mail.gmail.com> References: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> <560fb5ed1003151309u59fe8fd3i387258f38e084a9e@mail.gmail.com> Message-ID: On Mon, Mar 15, 2010 at 9:09 PM, Reinier Zwitserloot < reinier at zwitserloot.com> wrote: > #1 + #2 > > but it actually isn't. This looks like a single closure that adds argument > number 1 and argument number 2 together, but it doesn't _have_ to be. It > could also be two closures, the first one simply returning its first > argument, the second simply returning its second, which are added together. > Aside from having trouble even delimiting this notion, it also raises the > question: How many arguments are there (just because #3 isn't mentioned > doesn't technically mean it couldn't exist; plenty of times where you have a > method that takes an argument that your implementation ends up not using, > just so your method fits a certain interface), and what are their types? > I admit that I hadn't considered the case where one would like to ignore an argument. But I see two options a) Don't allow it. Makes things easy, but I do think it would be bad. b) Demand some extra delimiter to wrap the lambda expression. {#1 + #2} WRT the typing issue I don't see how you could produce an expression where the type isn't obvious. The example with #1 + #2 is clearly an error on it's own, with no extra context there is only Object, and Object isn't usable in an expression involving + in other words, remove the names of parameters, preferring numeric access > instead. This has the benefit of producing code that's smaller, but, I doubt > its worth the significant cost in doing it: #1 and #2 don't look anything > like any existing java concept, whereas naming the parameters does (it looks > like method parameters), in non-tiny closures the numbers are going to get > confusing (for obvious reasons; a number conveys less information than a > name. There's a reason we don't advocate naming your variables "a", "b", > "c", after all), and now the closure's signature is hard to distinguish from > a function type. > By adding extra syntax the benefit of the shorter syntax isn't there any more, so I'd say the cost of not having names aren't worth it. Another option is to use named arguments instead of numbered, and just say that the order of declaration determine their position in the argument list. {#arg1 + #arg2} But this could prove annoying when you really wan't to use them in a different order. Adding more syntax just makes it ugly {#(2)arg1 + #(1)arg2} and we might just as well go for (arg1,arg2) => arg1+arg2 An other possibility, but I assume this is a bit esoteric for Java, would be to match parameters on names instead of position when applying a lambda. (int,int)->int fun = {#arg1 + #arg2}; int result = fun.(arg1=4,arg2=3) BR, John From bobfoster at gmail.com Mon Mar 15 15:27:40 2010 From: bobfoster at gmail.com (Bob Foster) Date: Mon, 15 Mar 2010 15:27:40 -0700 Subject: # considered harmful [was C++11 lambdas] Message-ID: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> Harmful because it's unpleasant to look at and leads to indecipherable code. Every time someone proposes adding another #, the syntax gets uglier and less readable. I apologize for coming to this point rather late, but frankly once I read the # proposal and realized no one intended to implement actual closures, I decided the whole project was a plot to convert Java programmers to Scala and my mind turned to more pleasant things. This was a mistake, and Remi Forax's excellent counter-proposal has inspired me. Why _not_ try something simpler? I have a (very) few nits to pick with Remi's proposal: - int(int) is a function type, not a function. - the . has no place in function call syntax; functions are not methods. - I quite like the ( expr ) syntax when a function body is only a single expression, but it's not essential and if it were adopted should be extended to methods for consistency. - Java doesn't have type inference elsewhere, so it seems inconsistent to have it for functions. However, if it was going to be part of the # syntax, it should be allowed here, too, as Remi originally proposed, and extended to methods, as well. The whole proposal works syntactically because currently the construction Type() never appears in a valid program except after new. So as long as new doesn't pollute anonymous functions (a separate thread), function types are unambiguous to both the compiler and readers. A few examples: > A method that takes two function types and returns a lambda:[rewritten as] int(int,int) filter(int(int) filter, int(int,int) operation) { return int(int x, int y) { return operation(filter(x), filter(y)); } } Used with anonymous functions: int(int,int) f = filter(int(int i) { return i % 2 == 0 ? i : i/2*2;}, int(int x, int y) { return x*y;}); If you wanted to allow type inference for return types, it would look like: int(int,int) g = filter((int i) { return i % 2 == 0 ? i : i/2*2; }, (int x, int y) { return x*y; }); If you wanted to allow type inference and the parenthesis syntax: int(int,int) h = filter((int i)( i % 2 == 0 ? i : i/2*2 ), (int x, int y)( x*y )); (It's really hard not to like that, but see comment above.) A named function, not a method, inline or in a class: int(int,int) max = int(int x, int y) { return Math.max(x, y); } An anonymous function: Thread t = new Thread(void() { doSomething(); doMore(); }); The curry thing seems a bit of a botch at the moment. Surely it's a partial application, so the syntax should reflect that, and it should work for methods. class A { void foo(int x) { ... } void(int) fun = { ... } } // curry examples A a = new A(); void() f1 = a.foo(2) curry; void() f2 = a.foo() curry; void() f3 = A.fun(2) curry; f1(); f2(); f3(); To curry an anonymous function: int(int,int) fc = filter((int i)(), (int x, int y, int z)(Math.max(Math.max(x,y), z)(0) curry); assert fc(2, 5) == 4; assert fc(-2, -5) == 0; Bob On?Sun Mar 14 09:14:29 PDT 2010?R?mi Forax?forax at univ-mlv.fr??wrote: > Yes, seeing that I wonder if we are not going in the wrong direction by > trying > to protect lambda and function type by a # or some enclosing parens. > > Why not trying something simpler ? > > > A function that takes an int and returns an int: > int(int) > > A function that takes an int and returns nothing: > void(int) > > A function that takes two ints and returns an int: > int(int, int) > > A function that throws an Exception: > int(int) throws Exception > > A function that takes a function that throws an Exception: > int(int(int) throws Exception) > > A function that throws an Exception and takes a function > int(int(int)) throws Exception > > A function that takes an int and returns a function that returns an int > int() (int) > > curry! > R() throws E (R(A) throws E, A) curry = ... > > Grammar: > ResultType ( TypeList ) throws ExceptionList > > > And removing the # in the lambda syntax: > > int(int) fun = (int x) (x); ?// lambda expression > int(int) fun = (int x) { return x; }; ?// lambda block > > A method that returns a lambda: > int(int,int) plus() { > ? return (int x, int y) (x+y); > } > > A method that takes two function types and returns a lambda: > int(int,int) filter(int(int) filter, int(int,int) operation) { > ? return (int x, int y) { > ? ? return operation.(filter.(x), filter.(y)); > ? }; > } From bobfoster at gmail.com Mon Mar 15 15:36:34 2010 From: bobfoster at gmail.com (Bob Foster) Date: Mon, 15 Mar 2010 15:36:34 -0700 Subject: Inverted syntax option In-Reply-To: References: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> Message-ID: <47e7f7fd1003151536h7fd82ce6r5187099d0ca8bf11@mail.gmail.com> Monstrosity, indeed. How do you feel about Remy Forax's proposal, e.g.: baz((int x, int y)(x + y)) (since I gather you like type inference) or: baz(int(int x, int y)(x + y)) Cheers! Bob On Mon, Mar 15, 2010 at 2:56 PM, John Nilsson wrote: > On Mon, Mar 15, 2010 at 8:09 PM, Bob Foster wrote: >> >> Perhaps you meant this to illustrate how awkward and regressive this >> numbered-argument syntax is, and if so I applaud you for the examples. >> If this is a serious proposal, I suggest swapping the % character for # >> (the parser can figure it out by its prefix operator position) so everyone >> will understand that the new model for the Java language is the MS-DOS >> command line. >> ?? baz(%1 + %2) > > ;-) I was actually thinking of $1 + $2 (Bash style) but $ is already a valid > identifier as far as I know... > But yes it was intended as a serious proposal. If the alternative is some > monstrosity such as new lambda(int a, int b) { return a + b: } to > express a simple concept that shouldn't require more characters than one to > be perfectly clear: + > I'm quite found of the Scala approach to lambdas where syntax is mostly > optional when the context can be used to infer the intended lambda.?#1 + #2 > is kind of compromise in that regard as it has been my impression that the > Java crowd here isn't to found of terseness. > BR, > John From forax at univ-mlv.fr Mon Mar 15 15:47:36 2010 From: forax at univ-mlv.fr (=?UTF-8?B?UsOpbWkgRm9yYXg=?=) Date: Mon, 15 Mar 2010 23:47:36 +0100 Subject: C++11 lambdas In-Reply-To: <560fb5ed1003151511p8c4b227h9169303c2b50e5a0@mail.gmail.com> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> <4B9EAFCE.1010305@univ-mlv.fr> <560fb5ed1003151511p8c4b227h9169303c2b50e5a0@mail.gmail.com> Message-ID: <4B9EB908.1060100@univ-mlv.fr> Le 15/03/2010 23:11, Reinier Zwitserloot a ?crit : > On Mon, Mar 15, 2010 at 11:08 PM, R?mi Forax > wrote: > > I don't follow you. > What is the error the compiler should output ? > > > > Exactly. It's not clear anymore. The Java grammar already allows some common prefix for expressions and types. What is the error message for: (a) is a cast and (a Hence the compiler can choose to either emit one error, which means it > generates something very confusing in 50% of the cases, or, it can > choose to emit a rambling error that lists all the possible causes. > That was the point: This is a bad thing. With the # the intent is more > clear, which leads to better error messaging. As far as the compiler > is concerned, no #, no closure. Remember that from the strawman proposal you can find # in a function type, a lambda or a method reference. What is your proposed error message for a ill-formed snippet like this: #()int my guess is 'syntax error'. > The same thing happens right now in for example class declarations. If > you don't include a class declaration indicator ('class', 'interface', > or 'enum') both ecj and javac do not consider it a (botched) type > declaration. You can always improve error recovery knowing that both ecj and javac use hand written error recovery rules. R?mi From forax at univ-mlv.fr Mon Mar 15 15:57:05 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 15 Mar 2010 23:57:05 +0100 Subject: # considered harmful [was C++11 lambdas] In-Reply-To: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> References: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> Message-ID: <4B9EBB41.3080904@univ-mlv.fr> Le 15/03/2010 23:27, Bob Foster a ?crit : > Harmful because it's unpleasant to look at and leads to indecipherable > code. Every time someone proposes adding another #, the syntax gets > uglier and less readable. > > I apologize for coming to this point rather late, but frankly once I > read the # proposal and realized no one intended to implement actual > closures, I decided the whole project was a plot to convert Java > programmers to Scala and my mind turned to more pleasant things. This > was a mistake, and Remi Forax's excellent counter-proposal has > inspired me. Why _not_ try something simpler? > Yes, a supporter. > I have a (very) few nits to pick with Remi's proposal: > > - int(int) is a function type, not a function. > > - the . has no place in function call syntax; functions are not methods. > It will be cool to be able to call a function only by its name but it doesn't seem possible to twist the JLS invocation rules to do that (see the archive of this list for more info). > - I quite like the ( expr ) syntax when a function body is only a > single expression, but it's not essential and if it were adopted > should be extended to methods for consistency. > > - Java doesn't have type inference elsewhere, so it seems inconsistent > to have it for functions. However, if it was going to be part of the # > syntax, it should be allowed here, too, as Remi originally proposed, > and extended to methods, as well. > Java has type inference when resolving generic method calls and when using the diamond operator. > The whole proposal works syntactically because currently the > construction Type() never appears in a valid program except after new. > So as long as new doesn't pollute anonymous functions (a separate > thread), function types are unambiguous to both the compiler and > readers. > [...] R?mi From reinier at zwitserloot.com Mon Mar 15 16:33:40 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 16 Mar 2010 00:33:40 +0100 Subject: # considered harmful [was C++11 lambdas] In-Reply-To: <4B9EBB41.3080904@univ-mlv.fr> References: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> <4B9EBB41.3080904@univ-mlv.fr> Message-ID: <560fb5ed1003151633w6f2338fdj7a159e33e2b2ad8f@mail.gmail.com> Do you have *ANY* comments at all about the many many problems that this mailing list uncovered with your 'preferences', or are you just whining? A small and incomplete rehash: 1. No '.' Java has an almost unique take on namespaces, in that in java types, methods and variables all have their own namespace. Without that dot, the meaning of "foo()" is ambiguous. Are you invoking the method named 'foo', or are you invoking the closure pointed at by variable foo? The primary proposal started out without that dot, as per the strawman. In other words, we covered this. At extreme length. There's no point re-raising this issue unless you come up with different solutions for the namespace issues. IIRC, the dot has going for it: - No need for arbitrary ordering of namespaces in case foo is both a method and a variable. - Closures in java are to a smallish extent shoehorned in. They are unique things that aren't exactly like methods, so their invocation should look a little different. These advantages were deemed superior to the advantage that dotless invocation has, which one dot less clutter at the cost of syntax ambiguity. 2. "Actual closures" The word 'closures' is pretty meaningless. It has a well defined term in the academic sense, and, frankly, its definition is pretty well defined in the dictionary sense too, *but*, the vast majority of java programmers have been abusing the term to mean something different. At any rate, whining about "actual closures" misses the point completely. Project Lambda's aim is to create syntax that makes it easy to write a bunch of code that's bundled up into a reference so that you need not execute it on the spot, but can instead hand it off to for example another method, with as primary use case extra-jsr166y a.k.a. ParallelArrays. From the outset (the outset being Mark Reinhold's strawman at Devoxx '09) Project Lambda did not aim to add concepts like keeping control statements such as 'break', 'continue' and 'return' transparent. The aims of Project Lambda have not changed since its inception. Possibly you were just confused as to what they were. On Mon, Mar 15, 2010 at 11:57 PM, R?mi Forax wrote: > Le 15/03/2010 23:27, Bob Foster a ?crit : > > Harmful because it's unpleasant to look at and leads to indecipherable > > code. Every time someone proposes adding another #, the syntax gets > > uglier and less readable. > > > > I apologize for coming to this point rather late, but frankly once I > > read the # proposal and realized no one intended to implement actual > > closures, I decided the whole project was a plot to convert Java > > programmers to Scala and my mind turned to more pleasant things. This > > was a mistake, and Remi Forax's excellent counter-proposal has > > inspired me. Why _not_ try something simpler? > > > > Yes, a supporter. > > > I have a (very) few nits to pick with Remi's proposal: > > > > - int(int) is a function type, not a function. > > > > - the . has no place in function call syntax; functions are not methods. > > > > It will be cool to be able to call a function only by its name > but it doesn't seem possible to twist the JLS invocation rules > to do that (see the archive of this list for more info). > > > - I quite like the ( expr ) syntax when a function body is only a > > single expression, but it's not essential and if it were adopted > > should be extended to methods for consistency. > > > > - Java doesn't have type inference elsewhere, so it seems inconsistent > > to have it for functions. However, if it was going to be part of the # > > syntax, it should be allowed here, too, as Remi originally proposed, > > and extended to methods, as well. > > > > Java has type inference when resolving generic method calls and > when using the diamond operator. > > > The whole proposal works syntactically because currently the > > construction Type() never appears in a valid program except after new. > > So as long as new doesn't pollute anonymous functions (a separate > > thread), function types are unambiguous to both the compiler and > > readers. > > > > [...] > > R?mi > > From reinier at zwitserloot.com Mon Mar 15 16:38:49 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 16 Mar 2010 00:38:49 +0100 Subject: C++11 lambdas In-Reply-To: <4B9EB908.1060100@univ-mlv.fr> References: <4b4f45e01003140621h4df21827y73064286dc0dfbbb@mail.gmail.com> <15e8b9d21003140731u122c6f6fwc87fcd622b1a82fd@mail.gmail.com> <4B9D0B65.6060508@univ-mlv.fr> <560fb5ed1003151333j74d726b7n3c858ddab15a8076@mail.gmail.com> <4B9EAFCE.1010305@univ-mlv.fr> <560fb5ed1003151511p8c4b227h9169303c2b50e5a0@mail.gmail.com> <4B9EB908.1060100@univ-mlv.fr> Message-ID: <560fb5ed1003151638v717dfcefg51c1d705cd01dd86@mail.gmail.com> On Mon, Mar 15, 2010 at 11:47 PM, R?mi Forax wrote: > What is the error message for: > (a knowing that (a) is a cast and (a > The error would obviously be that the < is unmatched, and once you solve that, that the ( is unmatched. FWIW, yes, casts are a source of confusing error messages. Just because java already has a few of these scenarios doesn't excuse a new proposal from worrying about them. On the contrary, the more such confusing scenarios java has, the more important it is that new ones aren't introduced. > I suppose the error message is something like 'syntax error' so > I continue to don't see your point here. > Try it. Java doesn't generate unqualified Syntax Errors. That's one of the many things that makes javac a bit different from new experiments like haskell or scala*, which pretty much bite your head off with an utterly confusing error message that probably doesn't even point at the proper location when you write a syntax error in your code. > Remember that from the strawman proposal you can find # in a function type, > a lambda or a method reference. > I don't think the strawman had method references. I didn't think the current status quo proposal does, either. It's either in a function type (something I've been championing to eliminate, as being unnecessary), or in a lambda, which are highly related. > What is your proposed error message for a ill-formed snippet like this: > #()int > > my guess is 'syntax error'. > > Not an acceptable error message. You can always improve error recovery knowing that both ecj and javac use > hand written > error recovery rules. > > Yes. Up to a point. Once a human can no longer tell what you were trying to do, it's pretty clear a compiler doesn't stand a snowball's chance to do any better, and in the case of something like "int();" I certainly can't tell if that's a botched attempt to call a method named 'int', or a dangling function type. From bobfoster at gmail.com Mon Mar 15 19:07:58 2010 From: bobfoster at gmail.com (Bob Foster) Date: Mon, 15 Mar 2010 19:07:58 -0700 Subject: # considered harmful [was C++11 lambdas] In-Reply-To: <560fb5ed1003151633w6f2338fdj7a159e33e2b2ad8f@mail.gmail.com> References: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> <4B9EBB41.3080904@univ-mlv.fr> <560fb5ed1003151633w6f2338fdj7a159e33e2b2ad8f@mail.gmail.com> Message-ID: <47e7f7fd1003151907r21e288e6k9b7300544e61c399@mail.gmail.com> On Mon, Mar 15, 2010 at 4:33 PM, Reinier Zwitserloot wrote: > Do you have *ANY* comments at all about the many many problems that this > mailing list uncovered with your 'preferences', or are you just whining? One person's opinions are another's whining, whatever. I have a day job, so I get the digest and don't follow this list moment by moment. If someone copies me, I reply. I've already apologized for coming late to the party. Once is enough. > A small and incomplete rehash: > 1. No '.' > Java has an almost unique take on namespaces, in that in java types, methods > and variables all have their own namespace. Without that dot, the meaning of > "foo()" is ambiguous. Are you invoking the method named 'foo', or are you > invoking the closure pointed at by variable foo? Agreed that within a class a reference to a method and a call through a variable of function type with the same number and type of arguments would be ambiguous. Using . as a prefix operator for indirect function calls with that issue is as good a device as any. You still have a problem with references to static function variables within a class and references outside the class, unless the proposal is to double up the dots, like: A..foo() a..foo() Regardless, such notation should be required _only_ if the call would be actually ambiguous, a fairly minor use case. Inside a class, a field name is not required to be qualified by 'this' unless necessary to disambiguate the reference; a static method name is not required to be qualified by the class name unless necessary to disambiguate from a non-static method. This should be treated the same. The example I was looking at, however, involved only function type arguments, and I see no reason to saddle references to argument names or local variables with gratuitous dots. As long as "inner functions" can only be defined through variables, there is no namespace issue and the scope rules handle the rest. > The primary proposal > started out without that dot, as per the strawman. In other words, we > covered this. At extreme length. There's no point re-raising this issue > unless you come up with different solutions for the namespace issues. IIRC, > the dot has going for it: > ?- No need for arbitrary ordering of namespaces in case foo is both a method > and a variable. > ?- Closures in java are to a smallish extent shoehorned in. They are unique > things that aren't exactly like methods, so their invocation should look a > little different. > These advantages were deemed superior to the advantage that dotless > invocation has, which one dot less clutter at the cost of syntax ambiguity. Ah, deemed. > 2. "Actual closures" > The word 'closures' is pretty meaningless. It has a well defined term in the > academic sense, and, frankly, its definition is pretty well defined in the > dictionary sense too, *but*, the vast majority of java programmers have been > abusing the term to mean something different. At any rate, whining about > "actual closures" misses the point completely. Project Lambda's aim is to > create syntax that makes it easy to write a bunch of code that's bundled up > into a reference so that you need not execute it on the spot, but can > instead hand it off to for example another method, with as primary use case > extra-jsr166y a.k.a. ParallelArrays. From the outset (the outset being Mark > Reinhold's strawman at Devoxx '09) Project Lambda did not aim to add > concepts like keeping control statements such as 'break', 'continue' and > 'return' transparent. The aims of Project Lambda have not changed since its > inception. Possibly you were just confused as to what they were. I agree it's pretty meaningless in this forum, and I wish you would stop referring to functions as closures. If nobody agrees what a closure is, it's insulting. If you care, though, I mean closures as they are meant, according to Wikipedia, in computer science: "a closure is a first-class function with free variables that are bound in the lexical environment." When I say that the proposal doesn't do real closures what I mean is it does lexically closed named constants. Better than nothing but a bit tedious to work around by hand. (Even considering break, etc. must mean someone confuses closures with Smalltalk blocks and their spawn.) Bob > > > On Mon, Mar 15, 2010 at 11:57 PM, R?mi Forax wrote: >> >> Le 15/03/2010 23:27, Bob Foster a ?crit : >> > Harmful because it's unpleasant to look at and leads to indecipherable >> > code. Every time someone proposes adding another #, the syntax gets >> > uglier and less readable. >> > >> > I apologize for coming to this point rather late, but frankly once I >> > read the # proposal and realized no one intended to implement actual >> > closures, I decided the whole project was a plot to convert Java >> > programmers to Scala and my mind turned to more pleasant things. This >> > was a mistake, and Remi Forax's excellent counter-proposal has >> > inspired me. Why _not_ try something simpler? >> > >> >> Yes, a supporter. >> >> > I have a (very) few nits to pick with Remi's proposal: >> > >> > - int(int) is a function type, not a function. >> > >> > - the . has no place in function call syntax; functions are not methods. >> > >> >> It will be cool to be able to call a function only by its name >> but it doesn't seem possible to twist the JLS invocation rules >> to do that (see the archive of this list for more info). >> >> > - I quite like the ( expr ) syntax when a function body is only a >> > single expression, but it's not essential and if it were adopted >> > should be extended to methods for consistency. >> > >> > - Java doesn't have type inference elsewhere, so it seems inconsistent >> > to have it for functions. However, if it was going to be part of the # >> > syntax, it should be allowed here, too, as Remi originally proposed, >> > and extended to methods, as well. >> > >> >> Java has type inference when resolving generic method calls and >> when using the diamond operator. >> >> > The whole proposal works syntactically because currently the >> > construction Type() never appears in a valid program except after new. >> > So as long as new doesn't pollute anonymous functions (a separate >> > thread), function types are unambiguous to both the compiler and >> > readers. >> > >> >> [...] >> >> R?mi >> > > From reinier at zwitserloot.com Mon Mar 15 21:55:45 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 16 Mar 2010 05:55:45 +0100 Subject: # considered harmful [was C++11 lambdas] In-Reply-To: <47e7f7fd1003151907r21e288e6k9b7300544e61c399@mail.gmail.com> References: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> <4B9EBB41.3080904@univ-mlv.fr> <560fb5ed1003151633w6f2338fdj7a159e33e2b2ad8f@mail.gmail.com> <47e7f7fd1003151907r21e288e6k9b7300544e61c399@mail.gmail.com> Message-ID: <560fb5ed1003152155h33721006v5653e51a9d8e5cd@mail.gmail.com> So, postfix dots are bad, but when your favourite proposal ends up being ambiguous, it's okay to add double prefix dots. Hm. Doesn't seem fair. It's just not that simple. Shadowing a field with a local variable declaration is, well, local. It occurs within the method itself. For closure invoke vs. method invoke this granularity level all of a sudden becomes the class. It doesn't really make the no-dot proposal any simpler than the dot proposal, and you haven't addressed any of the other concerns (closure invokes are a different concept compared to method invokes, and a visual cue is nice). It's insulting when nobody agrees with closures mean? The folks that are actually writing the proposal seem to agree. It also seems a bit odd to hold lambda-dev responsible for the fact that the 'closure' term has been watered down so much due to usage that goes back many years, well before lambda-dev was set up. You seem to be mistaken about how the status quo proposal closes around local variables. It does close around *ALL* of them. The one difference with most other languages is that the compiler, while it fully understands what you meant, refuses to compile it until you tell the compiler that you really did intend for the compiler to declare that variable on the heap, accept that thread synchronization issues can now crop up, and other such issues. This, too, has been covered, at length. The JVM memory model cannot be adapted to let closures access and mutate local variables of their outer scope trivially, and not even after some thought, so without some breakthrough proposal to show how this is doable this remains off the table. Which leaves the compiler generating a bunch of sugar to make it happen. Does this mean "volatile" can be put on any local variable, or only on local variables that are secretly heap-hosted? Does this mean that heap-hosted local variables are initialized to null/false/0 the way fields are, or is all usage in closures restricted to require definitive assignment prior to the closure even being defined, with a further restriction that no closure can set a final unset local? You're also going to create surprise code: Runnable[] runnables = new Runnable[3]; for (int i = 0; i < 3; i++) runnables[i] = #() {System.out.print(i);}; for (int i = 0; i < 3; i++) runnables[i].run(); This will print "333" in your proposal - quite the surprise. It'll not compile in the status quo as the closure is accessing mutated local variables. How do you suggest this is handled? Let it pass and decide that the masses that are going to stumble on this will just have to become smarter, and perhaps tell Oracle to hire a dedicated guy to respond to the avalance of reports at bugs.sun.com? Perhaps an exemption should be made for local variables declared in a basic for's init, and we should say _those_ variables cannot be closed over to avoid this problem. But then the proposal isn't as simple and straightforward as you seem to think, and it would help a great deal if you could produce a thorough list of exactly how your proposal works that includes such corner cases. NB: I take it you're aware that the status quo proposal allows closures to access *final* locals, just like this is legal in Anonymous Inner Classes in today's java? It's also (IIRC) on the fence leaning towards allowing access to effectively final locals (locals that aren't marked final but are nevertheless set exactly once, and this set occurs before the closure is defined) by treating the local declaration as implicitly final. You're getting awfully worked up about postfix dot and the need to mark *mutated* local variable declarations that are accessed in a closure, given that for both of those, there's no simple answer. --Reinier Zwitserloot On Tue, Mar 16, 2010 at 3:07 AM, Bob Foster wrote: > On Mon, Mar 15, 2010 at 4:33 PM, Reinier Zwitserloot > wrote: > > Do you have *ANY* comments at all about the many many problems that this > > mailing list uncovered with your 'preferences', or are you just whining? > > One person's opinions are another's whining, whatever. I have a day > job, so I get the digest and don't follow this list moment by moment. > If someone copies me, I reply. > > I've already apologized for coming late to the party. Once is enough. > > > A small and incomplete rehash: > > 1. No '.' > > Java has an almost unique take on namespaces, in that in java types, > methods > > and variables all have their own namespace. Without that dot, the meaning > of > > "foo()" is ambiguous. Are you invoking the method named 'foo', or are you > > invoking the closure pointed at by variable foo? > > Agreed that within a class a reference to a method and a call through > a variable of function type with the same number and type of arguments > would be ambiguous. Using . as a prefix operator for indirect function > calls with that issue is as good a device as any. You still have a > problem with references to static function variables within a class > and references outside the class, unless the proposal is to double up > the dots, like: > > A..foo() > a..foo() > > Regardless, such notation should be required _only_ if the call would > be actually ambiguous, a fairly minor use case. Inside a class, a > field name is not required to be qualified by 'this' unless necessary > to disambiguate the reference; a static method name is not required to > be qualified by the class name unless necessary to disambiguate from a > non-static method. This should be treated the same. > > The example I was looking at, however, involved only function type > arguments, and I see no reason to saddle references to argument names > or local variables with gratuitous dots. As long as "inner functions" > can only be defined through variables, there is no namespace issue and > the scope rules handle the rest. > > > The primary proposal > > started out without that dot, as per the strawman. In other words, we > > covered this. At extreme length. There's no point re-raising this issue > > unless you come up with different solutions for the namespace issues. > IIRC, > > the dot has going for it: > > - No need for arbitrary ordering of namespaces in case foo is both a > method > > and a variable. > > - Closures in java are to a smallish extent shoehorned in. They are > unique > > things that aren't exactly like methods, so their invocation should look > a > > little different. > > These advantages were deemed superior to the advantage that dotless > > invocation has, which one dot less clutter at the cost of syntax > ambiguity. > > Ah, deemed. > > > 2. "Actual closures" > > The word 'closures' is pretty meaningless. It has a well defined term in > the > > academic sense, and, frankly, its definition is pretty well defined in > the > > dictionary sense too, *but*, the vast majority of java programmers have > been > > abusing the term to mean something different. At any rate, whining about > > "actual closures" misses the point completely. Project Lambda's aim is to > > create syntax that makes it easy to write a bunch of code that's bundled > up > > into a reference so that you need not execute it on the spot, but can > > instead hand it off to for example another method, with as primary use > case > > extra-jsr166y a.k.a. ParallelArrays. From the outset (the outset being > Mark > > Reinhold's strawman at Devoxx '09) Project Lambda did not aim to add > > concepts like keeping control statements such as 'break', 'continue' and > > 'return' transparent. The aims of Project Lambda have not changed since > its > > inception. Possibly you were just confused as to what they were. > > I agree it's pretty meaningless in this forum, and I wish you would > stop referring to functions as closures. If nobody agrees what a > closure is, it's insulting. > > If you care, though, I mean closures as they are meant, according to > Wikipedia, in computer science: "a closure is a first-class function > with free variables that are bound in the lexical environment." When I > say that the proposal doesn't do real closures what I mean is it does > lexically closed named constants. Better than nothing but a bit > tedious to work around by hand. > > (Even considering break, etc. must mean someone confuses closures with > Smalltalk blocks and their spawn.) > > Bob > > > > > > > On Mon, Mar 15, 2010 at 11:57 PM, R?mi Forax wrote: > >> > >> Le 15/03/2010 23:27, Bob Foster a ?crit : > >> > Harmful because it's unpleasant to look at and leads to indecipherable > >> > code. Every time someone proposes adding another #, the syntax gets > >> > uglier and less readable. > >> > > >> > I apologize for coming to this point rather late, but frankly once I > >> > read the # proposal and realized no one intended to implement actual > >> > closures, I decided the whole project was a plot to convert Java > >> > programmers to Scala and my mind turned to more pleasant things. This > >> > was a mistake, and Remi Forax's excellent counter-proposal has > >> > inspired me. Why _not_ try something simpler? > >> > > >> > >> Yes, a supporter. > >> > >> > I have a (very) few nits to pick with Remi's proposal: > >> > > >> > - int(int) is a function type, not a function. > >> > > >> > - the . has no place in function call syntax; functions are not > methods. > >> > > >> > >> It will be cool to be able to call a function only by its name > >> but it doesn't seem possible to twist the JLS invocation rules > >> to do that (see the archive of this list for more info). > >> > >> > - I quite like the ( expr ) syntax when a function body is only a > >> > single expression, but it's not essential and if it were adopted > >> > should be extended to methods for consistency. > >> > > >> > - Java doesn't have type inference elsewhere, so it seems inconsistent > >> > to have it for functions. However, if it was going to be part of the # > >> > syntax, it should be allowed here, too, as Remi originally proposed, > >> > and extended to methods, as well. > >> > > >> > >> Java has type inference when resolving generic method calls and > >> when using the diamond operator. > >> > >> > The whole proposal works syntactically because currently the > >> > construction Type() never appears in a valid program except after new. > >> > So as long as new doesn't pollute anonymous functions (a separate > >> > thread), function types are unambiguous to both the compiler and > >> > readers. > >> > > >> > >> [...] > >> > >> R?mi > >> > > > > > From john at milsson.nu Tue Mar 16 09:47:00 2010 From: john at milsson.nu (John Nilsson) Date: Tue, 16 Mar 2010 17:47:00 +0100 Subject: Inverted syntax option In-Reply-To: <47e7f7fd1003151536h7fd82ce6r5187099d0ca8bf11@mail.gmail.com> References: <47e7f7fd1003151209s5faf0ea1m31743894240f870@mail.gmail.com> <47e7f7fd1003151536h7fd82ce6r5187099d0ca8bf11@mail.gmail.com> Message-ID: On Mon, Mar 15, 2010 at 11:36 PM, Bob Foster wrote: > Monstrosity, indeed. How do you feel about Remy Forax's proposal, e.g.: > > baz((int x, int y)(x + y)) > > (since I gather you like type inference) or: > > baz(int(int x, int y)(x + y)) As you gather I actually preferr the top one ;-) (but then you could just as well inferr the argument types too: (x,y)(x+y) ) Compared to most suggestions so for this one is actually bearable. Maybe some minor tweaks to improve readability though. I think either the argument list, or the actual expression, or maybe the whole thing, needs to have a different wrapping, two parenthesies looks to symetric for something that is completley different. // Remove superflous parenthesis, makes it look more like a cast where unbound variables are declared... baz((int x, int y) x+y) // If the argument list should resembel a method declaration, so should the "body", no return though. baz((int x, int y){x+y}) // The argument list as an annotation to an expression; baz((x+y)) baz([int x, int y](x+y)) baz({int x, int y}(x+y)) baz(|int x, int y| (x+y)) baz((|int x, int y| x+y)) baz(@(int x, int y) x+y) baz((int x, int y)@(x+y)) // Go full out lambda ! (Inferred types) baz(?x,y . x + y) BR, John From peter.levart at gmail.com Tue Mar 16 17:13:40 2010 From: peter.levart at gmail.com (Peter Levart) Date: Wed, 17 Mar 2010 01:13:40 +0100 Subject: Something simpler? Message-ID: <201003170113.40897.peter.levart@gmail.com> In light of recent Remi Forax's plea for simpler syntax, in light of of '#' and '.(' considered harmful, in light of Neal Gafter's blog about desirable orthogonality of language features: http://gafter.blogspot.com/2006/09/failure-of-imagination-in-language_17.html and above all in light of Lawrence Kesteloot's writing: http://www.teamten.com/lawrence/writings/the_language_squint_test.html which extends "orthogonality" to syntax as well, here's my 3rd attempt at a simpler syntax: FunctionType: '[' ParameterTypes_opt ':' ResultType Throws_opt ']' ExpressionLambda: '(' ParameterList_opt ':' Expression ')' StatementLambda: '{' ParameterList_opt ':' Statements '}' FunctionInvocationExpression: FunctionTypedExpression '[' ExpressionList_opt ']' examples: [:int] two = (:2); assert two[] == 2; [File:String throws IOException] readFile = { File f: Reader in = new FileReader(f); try { char[] buf = new char[8192]; StringBuilder sb = new StringBuilder(); int nread; while ((nread = in.read(buf)) >= 0) sb.append(buf, 0, nread); return sb.toString(); } finally { try { in.close(); } catch (IOException e) { // ignore } } }; String text = readFile[new File("/etc/passwd")]; [[A:R throws E], A : [:R throws E]] curry = ([A:R throws E] lambda, A arg : (:lambda[arg])); [[A:R throws E], A : [:R throws E]] curry2 = { [A:R throws E] lambda, A arg : return (:lambda[arg]); }; [A:R throws E] lambda = { A a: if (a == null) throw new E(); return new R(a); }; [:R throws E] curried = curry[lambda, new A()]; R r = curried[]; discussion: I know, I know, '[]' are reserved for arrays. But so are '()' - for expressions, method/constructor params and casts. The point is that '()' are very much abused in current 0.15 lambda proposal for function types as well as lambdas (just look at expression lambda potentially containing 3 pairs of '()' in single construct). Lambda and function-typed heavy code is starting to look like Lisp - not very Java like. The point that Lawrance Kesteloot beautifully explains in his writing is that different things combined together should visually fall-apart - they should be easily decomposable into components. Since function type / array type combinations are deprecated anyway, this proposal steps right onto the syntax tokens that are traditionally reserved for arrays. It does not prevent combinations of function types and array types but it makes the less used combination more awkward-looking to benefit other more useful combinations (like casting to function types, specifying function-typed parameters in methods, chaining method and function calls). The syntax of expression lambda is similar to parenthesized expression. It just adds optional formal parameters and a mandatory delimiter immediately after opening '('. Likewise the syntax of statement lambda is similar to block statement. It just adds optional formal parameters and a mandatory delimiter immediately after opening '{': (12) vs. (:12) { System.out.println(); } vs . {: System.out.println(); } Regards, Peter From neal at gafter.com Tue Mar 16 17:25:03 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 16 Mar 2010 17:25:03 -0700 Subject: Something simpler? In-Reply-To: <201003170113.40897.peter.levart@gmail.com> References: <201003170113.40897.peter.levart@gmail.com> Message-ID: <15e8b9d21003161725g16a5b9cfkf52d7a9d15c4663@mail.gmail.com> Peter- This isn't bad, but I think the colon is far too subtle. It also fails to naturally support a possible future extension of further type inference, because {name:statement} could either be a lambda expression with one parameter whose type is inferred, or a block containing a labeled statement. Cheers, Neal On Tue, Mar 16, 2010 at 5:13 PM, Peter Levart wrote: > In light of recent Remi Forax's plea for simpler syntax, in light of of '#' and '.(' considered > harmful, in light of Neal Gafter's blog about desirable orthogonality of language features: > > http://gafter.blogspot.com/2006/09/failure-of-imagination-in-language_17.html > > and above all in light of Lawrence Kesteloot's writing: > > http://www.teamten.com/lawrence/writings/the_language_squint_test.html > > which extends "orthogonality" to syntax as well, here's my 3rd attempt at a simpler syntax: > > > FunctionType: > ? ?'[' ParameterTypes_opt ':' ResultType Throws_opt ']' > > ExpressionLambda: > ? ?'(' ParameterList_opt ':' Expression ')' > > StatementLambda: > ? ?'{' ParameterList_opt ':' Statements '}' > > FunctionInvocationExpression: > ? ?FunctionTypedExpression '[' ExpressionList_opt ']' > > > examples: > > > [:int] two = (:2); > > assert two[] == 2; > > > [File:String throws IOException] readFile = { > ?File f: > ? ?Reader in = new FileReader(f); > ? ?try { > ? ? ?char[] buf = new char[8192]; > ? ? ?StringBuilder sb = new StringBuilder(); > ? ? ?int nread; > ? ? ?while ((nread = in.read(buf)) >= 0) > ? ? ? ?sb.append(buf, 0, nread); > ? ? ?return sb.toString(); > ? ?} > ? ?finally { > ? ? ?try { in.close(); } catch (IOException e) { // ignore } > ? ?} > }; > > String text = readFile[new File("/etc/passwd")]; > > > [[A:R throws E], A : [:R throws E]] curry = ([A:R throws E] lambda, A arg : (:lambda[arg])); > > [[A:R throws E], A : [:R throws E]] curry2 = { > ?[A:R throws E] lambda, A arg : > ? ?return (:lambda[arg]); > }; > > [A:R throws E] lambda = { > ?A a: > ? ?if (a == null) > ? ? ?throw new E(); > ? ?return new R(a); > }; > > [:R throws E] curried = curry[lambda, new A()]; > > R r = curried[]; > > > discussion: > > > I know, I know, '[]' are reserved for arrays. But so are '()' ?- for expressions, > method/constructor params and casts. The point is that '()' are very much abused in current 0.15 > lambda proposal for function types as well as lambdas (just look at expression lambda > potentially containing 3 pairs of '()' in single construct). Lambda and function-typed heavy > code is starting to look like Lisp - not very Java like. The point that Lawrance Kesteloot > beautifully explains in his writing is that different things combined together should visually > fall-apart - they should be easily decomposable into components. > > Since function type / array type combinations are deprecated anyway, this proposal steps right > onto the syntax tokens that are traditionally reserved for arrays. It does not prevent > combinations of function types and array types but it makes the less used combination more > awkward-looking to benefit other more useful combinations (like casting to function types, > specifying function-typed parameters in methods, chaining method and function calls). > > The syntax of expression lambda is similar to parenthesized expression. It just adds optional > formal parameters and a mandatory delimiter immediately after opening '('. Likewise the syntax > of statement lambda is similar to block statement. It just adds optional formal parameters and a > mandatory delimiter immediately after opening '{': > > (12) vs. (:12) > > { System.out.println(); } vs . {: System.out.println(); } > > > Regards, Peter > > From collin.fagan at gmail.com Tue Mar 16 17:35:35 2010 From: collin.fagan at gmail.com (Collin Fagan) Date: Tue, 16 Mar 2010 18:35:35 -0600 Subject: Using : for Lambda Syntax [was # considered harmful [was C++11 lambdas]] Message-ID: Hi Everyone, I've been listening for a while and thought maybe I could contribute a few ideas. Can we use : in the lambda syntax? Off the top of my head I think it's only used in the for-each loop and the ternary operator. If : is up for grabs then my next question is: can we infix this operator instead of prefixing it? Examples: (borrowed from an earlier post by R?mi Forax) A function that takes an int and returns an int: int(int) becomes int:(int) and ... A function that takes an int and returns nothing: void:(int) A function that takes two ints and returns an int: int:(int, int) A function that throws an Exception: int:(int) throws Exception A function that takes a function that throws an Exception: int:(int:(int) throws Exception) Grammar: ResultType :( TypeList ) throws ExceptionList This syntax reads left to right in a way that is similar to method signatures, with the method name replaced by a ':' . Now when we get to the curry examples I would like to customize the assignment operator. Since I chose ':' how about using ':=' as the "curry operator" ? Examples: (borrowed from an earlier post by Bob Foster) class A { void foo(int x) { ... } void :(int) fun = { ... } } // curry examples A a = new A(); void:() f1 := a.foo(2); void:() f2 := a.foo(); void:() f3 := A.fun(2); Finally, to stay with the theme, invoking a lambda would use '::' f1::(); f2::(); f3::(); Optionally this syntax could be: f1.:(); or f1:.(); but I found neither of those particularly compelling. I *think* the : is no harder to type then the #. (At least on the English keyboards I'm used to.) The := construct is used in other languages (like Pascal, Eiffel and Smalltalk) but admittedly not for curring. The :: construct is used in C++, but again, not in the way I plan on using it. I could continue to flesh this out into a real proposal if people found the syntax compelling. If I've committed any egregious sin in my post I apologize. Thank you, - Collin On Mon, Mar 15, 2010 at 10:55 PM, Reinier Zwitserloot wrote: > So, postfix dots are bad, but when your favourite proposal ends up being > ambiguous, it's okay to add double prefix dots. Hm. Doesn't seem fair. > > It's just not that simple. Shadowing a field with a local variable > declaration is, well, local. It occurs within the method itself. For closure > invoke vs. method invoke this granularity level all of a sudden becomes the > class. > > It doesn't really make the no-dot proposal any simpler than the dot > proposal, and you haven't addressed any of the other concerns (closure > invokes are a different concept compared to method invokes, and a visual cue > is nice). > > > It's insulting when nobody agrees with closures mean? The folks that are > actually writing the proposal seem to agree. It also seems a bit odd to hold > lambda-dev responsible for the fact that the 'closure' term has been watered > down so much due to usage that goes back many years, well before lambda-dev > was set up. > > You seem to be mistaken about how the status quo proposal closes around > local variables. It does close around *ALL* of them. The one difference with > most other languages is that the compiler, while it fully understands what > you meant, refuses to compile it until you tell the compiler that you really > did intend for the compiler to declare that variable on the heap, accept > that thread synchronization issues can now crop up, and other such issues. > > This, too, has been covered, at length. The JVM memory model cannot be > adapted to let closures access and mutate local variables of their outer > scope trivially, and not even after some thought, so without some > breakthrough proposal to show how this is doable this remains off the table. > Which leaves the compiler generating a bunch of sugar to make it happen. > > Does this mean "volatile" can be put on any local variable, or only on local > variables that are secretly heap-hosted? Does this mean that heap-hosted > local variables are initialized to null/false/0 the way fields are, or is > all usage in closures restricted to require definitive assignment prior to > the closure even being defined, with a further restriction that no closure > can set a final unset local? > > You're also going to create surprise code: > > Runnable[] runnables = new Runnable[3]; > for (int i = 0; i < 3; i++) runnables[i] = #() {System.out.print(i);}; > for (int i = 0; i < 3; i++) runnables[i].run(); > > This will print "333" in your proposal - quite the surprise. It'll not > compile in the status quo as the closure is accessing mutated local > variables. How do you suggest this is handled? Let it pass and decide that > the masses that are going to stumble on this will just have to become > smarter, and perhaps tell Oracle to hire a dedicated guy to respond to the > avalance of reports at bugs.sun.com? Perhaps an exemption should be made for > local variables declared in a basic for's init, and we should say _those_ > variables cannot be closed over to avoid this problem. But then the proposal > isn't as simple and straightforward as you seem to think, and it would help > a great deal if you could produce a thorough list of exactly how your > proposal works that includes such corner cases. > > NB: I take it you're aware that the status quo proposal allows closures to > access *final* locals, just like this is legal in Anonymous Inner Classes in > today's java? It's also (IIRC) on the fence leaning towards allowing access > to effectively final locals (locals that aren't marked final but are > nevertheless set exactly once, and this set occurs before the closure is > defined) by treating the local declaration as implicitly final. You're > getting awfully worked up about postfix dot and the need to mark *mutated* > local variable declarations that are accessed in a closure, given that for > both of those, there's no simple answer. > > --Reinier Zwitserloot > > > > On Tue, Mar 16, 2010 at 3:07 AM, Bob Foster wrote: > >> On Mon, Mar 15, 2010 at 4:33 PM, Reinier Zwitserloot >> wrote: >> > Do you have *ANY* comments at all about the many many problems that this >> > mailing list uncovered with your 'preferences', or are you just whining? >> >> One person's opinions are another's whining, whatever. I have a day >> job, so I get the digest and don't follow this list moment by moment. >> If someone copies me, I reply. >> >> I've already apologized for coming late to the party. Once is enough. >> >> > A small and incomplete rehash: >> > 1. No '.' >> > Java has an almost unique take on namespaces, in that in java types, >> methods >> > and variables all have their own namespace. Without that dot, the meaning >> of >> > "foo()" is ambiguous. Are you invoking the method named 'foo', or are you >> > invoking the closure pointed at by variable foo? >> >> Agreed that within a class a reference to a method and a call through >> a variable of function type with the same number and type of arguments >> would be ambiguous. Using . as a prefix operator for indirect function >> calls with that issue is as good a device as any. You still have a >> problem with references to static function variables within a class >> and references outside the class, unless the proposal is to double up >> the dots, like: >> >> A..foo() >> a..foo() >> >> Regardless, such notation should be required _only_ if the call would >> be actually ambiguous, a fairly minor use case. Inside a class, a >> field name is not required to be qualified by 'this' unless necessary >> to disambiguate the reference; a static method name is not required to >> be qualified by the class name unless necessary to disambiguate from a >> non-static method. This should be treated the same. >> >> The example I was looking at, however, involved only function type >> arguments, and I see no reason to saddle references to argument names >> or local variables with gratuitous dots. As long as "inner functions" >> can only be defined through variables, there is no namespace issue and >> the scope rules handle the rest. >> >> > The primary proposal >> > started out without that dot, as per the strawman. In other words, we >> > covered this. At extreme length. There's no point re-raising this issue >> > unless you come up with different solutions for the namespace issues. >> IIRC, >> > the dot has going for it: >> > ?- No need for arbitrary ordering of namespaces in case foo is both a >> method >> > and a variable. >> > ?- Closures in java are to a smallish extent shoehorned in. They are >> unique >> > things that aren't exactly like methods, so their invocation should look >> a >> > little different. >> > These advantages were deemed superior to the advantage that dotless >> > invocation has, which one dot less clutter at the cost of syntax >> ambiguity. >> >> Ah, deemed. >> >> > 2. "Actual closures" >> > The word 'closures' is pretty meaningless. It has a well defined term in >> the >> > academic sense, and, frankly, its definition is pretty well defined in >> the >> > dictionary sense too, *but*, the vast majority of java programmers have >> been >> > abusing the term to mean something different. At any rate, whining about >> > "actual closures" misses the point completely. Project Lambda's aim is to >> > create syntax that makes it easy to write a bunch of code that's bundled >> up >> > into a reference so that you need not execute it on the spot, but can >> > instead hand it off to for example another method, with as primary use >> case >> > extra-jsr166y a.k.a. ParallelArrays. From the outset (the outset being >> Mark >> > Reinhold's strawman at Devoxx '09) Project Lambda did not aim to add >> > concepts like keeping control statements such as 'break', 'continue' and >> > 'return' transparent. The aims of Project Lambda have not changed since >> its >> > inception. Possibly you were just confused as to what they were. >> >> I agree it's pretty meaningless in this forum, and I wish you would >> stop referring to functions as closures. If nobody agrees what a >> closure is, it's insulting. >> >> If you care, though, I mean closures as they are meant, according to >> Wikipedia, in computer science: "a closure is a first-class function >> with free variables that are bound in the lexical environment." When I >> say that the proposal doesn't do real closures what I mean is it does >> lexically closed named constants. Better than nothing but a bit >> tedious to work around by hand. >> >> (Even considering break, etc. must mean someone confuses closures with >> Smalltalk blocks and their spawn.) >> >> Bob >> >> > >> > >> > On Mon, Mar 15, 2010 at 11:57 PM, R?mi Forax wrote: >> >> >> >> Le 15/03/2010 23:27, Bob Foster a ?crit : >> >> > Harmful because it's unpleasant to look at and leads to indecipherable >> >> > code. Every time someone proposes adding another #, the syntax gets >> >> > uglier and less readable. >> >> > >> >> > I apologize for coming to this point rather late, but frankly once I >> >> > read the # proposal and realized no one intended to implement actual >> >> > closures, I decided the whole project was a plot to convert Java >> >> > programmers to Scala and my mind turned to more pleasant things. This >> >> > was a mistake, and Remi Forax's excellent counter-proposal has >> >> > inspired me. Why _not_ try something simpler? >> >> > >> >> >> >> Yes, a supporter. >> >> >> >> > I have a (very) few nits to pick with Remi's proposal: >> >> > >> >> > - int(int) is a function type, not a function. >> >> > >> >> > - the . has no place in function call syntax; functions are not >> methods. >> >> > >> >> >> >> It will be cool to be able to call a function only by its name >> >> but it doesn't seem possible to twist the JLS invocation rules >> >> to do that (see the archive of this list for more info). >> >> >> >> > - I quite like the ( expr ) syntax when a function body is only a >> >> > single expression, but it's not essential and if it were adopted >> >> > should be extended to methods for consistency. >> >> > >> >> > - Java doesn't have type inference elsewhere, so it seems inconsistent >> >> > to have it for functions. However, if it was going to be part of the # >> >> > syntax, it should be allowed here, too, as Remi originally proposed, >> >> > and extended to methods, as well. >> >> > >> >> >> >> Java has type inference when resolving generic method calls and >> >> when using the diamond operator. >> >> >> >> > The whole proposal works syntactically because currently the >> >> > construction Type() never appears in a valid program except after new. >> >> > So as long as new doesn't pollute anonymous functions (a separate >> >> > thread), function types are unambiguous to both the compiler and >> >> > readers. >> >> > >> >> >> >> [...] >> >> >> >> R?mi >> >> >> > >> > >> > > From pbenedict at apache.org Tue Mar 16 18:06:55 2010 From: pbenedict at apache.org (Paul Benedict) Date: Tue, 16 Mar 2010 20:06:55 -0500 Subject: Using : for Lambda Syntax [was # considered harmful [was C++11 lambdas]] In-Reply-To: References: Message-ID: Given a method using the "simple" syntax, wouldn't the ambiguity complained about disappear by making .invoke() mandatory? I still am a believer that function types should be treated like an object. It's almost akin to strongly-typed reflection. void somemethod(int(int) a) { a.invoke(2); } From reinier at zwitserloot.com Tue Mar 16 22:32:26 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 17 Mar 2010 06:32:26 +0100 Subject: Something simpler? In-Reply-To: <201003170113.40897.peter.levart@gmail.com> References: <201003170113.40897.peter.levart@gmail.com> Message-ID: <560fb5ed1003162232v7f821c2cm652d36658d1a2821@mail.gmail.com> First syntax proposal that is very different from the strawman that looks workable and pretty. In my experience, the vast majority of code is written and rendered in monospace fonts. In such a font a colon is unlikely to be subtle. Neal's block ambiguity comment is neither here nor there; just stripping types out of source snippets turns loads of java code ambiguous. In case you're worried, Neal, inference would most likely involve a symbol or keyword. Scala seems to be doing pretty well with 'val' and 'var' at least for local variable declarations. --Reinier Zwitserloot On Wed, Mar 17, 2010 at 1:13 AM, Peter Levart wrote: > In light of recent Remi Forax's plea for simpler syntax, in light of of '#' > and '.(' considered > harmful, in light of Neal Gafter's blog about desirable orthogonality of > language features: > > > http://gafter.blogspot.com/2006/09/failure-of-imagination-in-language_17.html > > and above all in light of Lawrence Kesteloot's writing: > > http://www.teamten.com/lawrence/writings/the_language_squint_test.html > > which extends "orthogonality" to syntax as well, here's my 3rd attempt at a > simpler syntax: > > > FunctionType: > '[' ParameterTypes_opt ':' ResultType Throws_opt ']' > > ExpressionLambda: > '(' ParameterList_opt ':' Expression ')' > > StatementLambda: > '{' ParameterList_opt ':' Statements '}' > > FunctionInvocationExpression: > FunctionTypedExpression '[' ExpressionList_opt ']' > > > examples: > > > [:int] two = (:2); > > assert two[] == 2; > > > [File:String throws IOException] readFile = { > File f: > Reader in = new FileReader(f); > try { > char[] buf = new char[8192]; > StringBuilder sb = new StringBuilder(); > int nread; > while ((nread = in.read(buf)) >= 0) > sb.append(buf, 0, nread); > return sb.toString(); > } > finally { > try { in.close(); } catch (IOException e) { // ignore } > } > }; > > String text = readFile[new File("/etc/passwd")]; > > > [[A:R throws E], A : [:R throws E]] curry = ([A:R throws E] lambda, A arg : > (:lambda[arg])); > > [[A:R throws E], A : [:R throws E]] curry2 = { > [A:R throws E] lambda, A arg : > return (:lambda[arg]); > }; > > [A:R throws E] lambda = { > A a: > if (a == null) > throw new E(); > return new R(a); > }; > > [:R throws E] curried = curry[lambda, new A()]; > > R r = curried[]; > > > discussion: > > > I know, I know, '[]' are reserved for arrays. But so are '()' - for > expressions, > method/constructor params and casts. The point is that '()' are very much > abused in current 0.15 > lambda proposal for function types as well as lambdas (just look at > expression lambda > potentially containing 3 pairs of '()' in single construct). Lambda and > function-typed heavy > code is starting to look like Lisp - not very Java like. The point that > Lawrance Kesteloot > beautifully explains in his writing is that different things combined > together should visually > fall-apart - they should be easily decomposable into components. > > Since function type / array type combinations are deprecated anyway, this > proposal steps right > onto the syntax tokens that are traditionally reserved for arrays. It does > not prevent > combinations of function types and array types but it makes the less used > combination more > awkward-looking to benefit other more useful combinations (like casting to > function types, > specifying function-typed parameters in methods, chaining method and > function calls). > > The syntax of expression lambda is similar to parenthesized expression. It > just adds optional > formal parameters and a mandatory delimiter immediately after opening '('. > Likewise the syntax > of statement lambda is similar to block statement. It just adds optional > formal parameters and a > mandatory delimiter immediately after opening '{': > > (12) vs. (:12) > > { System.out.println(); } vs . {: System.out.println(); } > > > Regards, Peter > > From jjb at google.com Wed Mar 17 01:10:35 2010 From: jjb at google.com (Joshua Bloch) Date: Wed, 17 Mar 2010 00:10:35 -0800 Subject: Something simpler? In-Reply-To: <201003170113.40897.peter.levart@gmail.com> References: <201003170113.40897.peter.levart@gmail.com> Message-ID: <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> I don't want to be the party pooper here, but this doesn't look at all like Java. I'm afraid it violates the cardinal rule of language extension: primum nil nocere. Josh On Tue, Mar 16, 2010 at 4:13 PM, Peter Levart wrote: > In light of recent Remi Forax's plea for simpler syntax, in light of of '#' > and '.(' considered > harmful, in light of Neal Gafter's blog about desirable orthogonality of > language features: > > > http://gafter.blogspot.com/2006/09/failure-of-imagination-in-language_17.html > > and above all in light of Lawrence Kesteloot's writing: > > http://www.teamten.com/lawrence/writings/the_language_squint_test.html > > which extends "orthogonality" to syntax as well, here's my 3rd attempt at a > simpler syntax: > > > FunctionType: > '[' ParameterTypes_opt ':' ResultType Throws_opt ']' > > ExpressionLambda: > '(' ParameterList_opt ':' Expression ')' > > StatementLambda: > '{' ParameterList_opt ':' Statements '}' > > FunctionInvocationExpression: > FunctionTypedExpression '[' ExpressionList_opt ']' > > > examples: > > > [:int] two = (:2); > > assert two[] == 2; > > > [File:String throws IOException] readFile = { > File f: > Reader in = new FileReader(f); > try { > char[] buf = new char[8192]; > StringBuilder sb = new StringBuilder(); > int nread; > while ((nread = in.read(buf)) >= 0) > sb.append(buf, 0, nread); > return sb.toString(); > } > finally { > try { in.close(); } catch (IOException e) { // ignore } > } > }; > > String text = readFile[new File("/etc/passwd")]; > > > [[A:R throws E], A : [:R throws E]] curry = ([A:R throws E] lambda, A arg : > (:lambda[arg])); > > [[A:R throws E], A : [:R throws E]] curry2 = { > [A:R throws E] lambda, A arg : > return (:lambda[arg]); > }; > > [A:R throws E] lambda = { > A a: > if (a == null) > throw new E(); > return new R(a); > }; > > [:R throws E] curried = curry[lambda, new A()]; > > R r = curried[]; > > > discussion: > > > I know, I know, '[]' are reserved for arrays. But so are '()' - for > expressions, > method/constructor params and casts. The point is that '()' are very much > abused in current 0.15 > lambda proposal for function types as well as lambdas (just look at > expression lambda > potentially containing 3 pairs of '()' in single construct). Lambda and > function-typed heavy > code is starting to look like Lisp - not very Java like. The point that > Lawrance Kesteloot > beautifully explains in his writing is that different things combined > together should visually > fall-apart - they should be easily decomposable into components. > > Since function type / array type combinations are deprecated anyway, this > proposal steps right > onto the syntax tokens that are traditionally reserved for arrays. It does > not prevent > combinations of function types and array types but it makes the less used > combination more > awkward-looking to benefit other more useful combinations (like casting to > function types, > specifying function-typed parameters in methods, chaining method and > function calls). > > The syntax of expression lambda is similar to parenthesized expression. It > just adds optional > formal parameters and a mandatory delimiter immediately after opening '('. > Likewise the syntax > of statement lambda is similar to block statement. It just adds optional > formal parameters and a > mandatory delimiter immediately after opening '{': > > (12) vs. (:12) > > { System.out.println(); } vs . {: System.out.println(); } > > > Regards, Peter > > From peter.levart at marand.si Wed Mar 17 01:20:42 2010 From: peter.levart at marand.si (Peter Levart) Date: Wed, 17 Mar 2010 09:20:42 +0100 Subject: Something simpler? In-Reply-To: <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> Message-ID: <201003170920.42301.peter.levart@marand.si> On 03/17/10, Joshua Bloch wrote: > I don't want to be the party pooper here, but this doesn't look at all like > Java. I'm afraid it violates the cardinal rule of language > extension: primum nil nocere. > > Josh > Which part of the proposed syntax do you feel does most harm? Regards, Peter From schulz at the-loom.de Wed Mar 17 02:40:51 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Wed, 17 Mar 2010 10:40:51 +0100 Subject: Summary: Function type syntax In-Reply-To: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> Message-ID: <4BA0A3A3.1000108@the-loom.de> For a better reading, I created a web page with the summary, updated to the latest proposal by Peter. The website only is a summed up list of proposals already part of this mailing list, so no additional information is stored compared to what is available from the mailing list itself. http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm Stefan From jjb at google.com Wed Mar 17 03:41:17 2010 From: jjb at google.com (Joshua Bloch) Date: Wed, 17 Mar 2010 02:41:17 -0800 Subject: Something simpler? In-Reply-To: <201003170920.42301.peter.levart@marand.si> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <201003170920.42301.peter.levart@marand.si> Message-ID: <17b2302a1003170341x2d172d6btdbf52c1c1200cdf1@mail.gmail.com> Peter, On Wed, Mar 17, 2010 at 12:20 AM, Peter Levart wrote: > On 03/17/10, Joshua Bloch wrote: > > I don't want to be the party pooper here, but this doesn't look at all > like > > Java. I'm afraid it violates the cardinal rule of language > > extension: primum nil nocere. > > > > Josh > > > > Which part of the proposed syntax do you feel does most harm? > Again, not to be a party pooper, but all of it. This does not look like Java: [:int] two = (:2); assert two[] == 2; Java programmers wouldn't understand it, and they wouldn't be comfortable with it once it was explained to them. I'm sorry to be so negative, but I really don't think this is a good direction. Josh From opinali at gmail.com Wed Mar 17 05:09:48 2010 From: opinali at gmail.com (Osvaldo Doederlein) Date: Wed, 17 Mar 2010 09:09:48 -0300 Subject: Something simpler? In-Reply-To: <17b2302a1003170341x2d172d6btdbf52c1c1200cdf1@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <201003170920.42301.peter.levart@marand.si> <17b2302a1003170341x2d172d6btdbf52c1c1200cdf1@mail.gmail.com> Message-ID: The (ab) use of [] for function types seems indeed ouf of place in Java, although it's hard to judge if we would just get used to it over time. When I see this code I tend to remember both Objective-C (uses [] for message expressions) and C# (uses [] for annotations). This can be considered either good (there's plenty precedent fo C-family languages that make heavy use of [] for arrays, but overload it for completely different tasks) and bad (we're throwing even more confusion to the mix, especially for polyglot programmers). Having said that, cross-language comparisons are interesting but we should focus on Java, and as a secondary priority, on its "children languages". Java 7 will have new syntax for literal collections, so it's a top concern to have lambda/function type syntax that goes well with that - Josh's proposal overloads both [] and {}, so they would interact with most lambda syntax proposals. It would be nice to see some examples of lambdas+collections in proposals for alternative lambda syntax. And if possible, it's certainly nice to keep some alignment with Scala, Groovy, and/or JavaFX Script. BTW, even being a JavaFX enthusiast myself, I must give kudos to Sun for not making any attempt, in Coin or Lambdas, to just copy existing syntax from JavaFX Script, so far a Sun-proprietary and non-JCP language. But all else being equal - whenever the debate boils down to aesthetics and not hard objective issues like ambiguities - stealing some syntax from other important JVM languages that have the same feature would be a GREAT service to developers. We don't really need to learn three or four completely different syntax for *basic* features like lambdas/functions. We don't want to have complex, expensive cross-language calls for any method that passes a lambda parameter. A+ Osvaldo 2010/3/17 Joshua Bloch > Peter, > > > On Wed, Mar 17, 2010 at 12:20 AM, Peter Levart >wrote: > > > On 03/17/10, Joshua Bloch wrote: > > > I don't want to be the party pooper here, but this doesn't look at all > > like > > > Java. I'm afraid it violates the cardinal rule of language > > > extension: primum nil nocere. > > > > > > Josh > > > > > > > Which part of the proposed syntax do you feel does most harm? > > > > Again, not to be a party pooper, but all of it. This does not look like > Java: > > [:int] two = (:2); > assert two[] == 2; > > > Java programmers wouldn't understand it, and they wouldn't be comfortable > with it once it was explained to them. I'm sorry to be so negative, but I > really don't think this is a good direction. > > Josh > > From bobfoster at gmail.com Wed Mar 17 11:54:48 2010 From: bobfoster at gmail.com (Bob Foster) Date: Wed, 17 Mar 2010 11:54:48 -0700 Subject: # considered harmful [was C++11 lambdas] In-Reply-To: <560fb5ed1003152155h33721006v5653e51a9d8e5cd@mail.gmail.com> References: <47e7f7fd1003151527w5b98d2d2xd5a4b5d422878bb5@mail.gmail.com> <4B9EBB41.3080904@univ-mlv.fr> <560fb5ed1003151633w6f2338fdj7a159e33e2b2ad8f@mail.gmail.com> <47e7f7fd1003151907r21e288e6k9b7300544e61c399@mail.gmail.com> <560fb5ed1003152155h33721006v5653e51a9d8e5cd@mail.gmail.com> Message-ID: <47e7f7fd1003171154y630b88a4s425bb0c2756e1735@mail.gmail.com> > The JVM memory model cannot be adapted to let closures access and mutate local > variables of their outer scope trivially, and not even after some thought, so without > some breakthrough proposal to show how this is doable this remains off the table. Scala manages to do it using the JVM. Hardly breakthrough: The compiler moves variables that are or could be modified in an inner function to an object on the heap and makes all references to those variables indirect. People use the same trick today when they want multiple return values; this just adds syntactic sugar. > [...] Bob From john at milsson.nu Wed Mar 17 12:29:40 2010 From: john at milsson.nu (John Nilsson) Date: Wed, 17 Mar 2010 20:29:40 +0100 Subject: Something simpler? In-Reply-To: References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <201003170920.42301.peter.levart@marand.si> <17b2302a1003170341x2d172d6btdbf52c1c1200cdf1@mail.gmail.com> Message-ID: On Wed, Mar 17, 2010 at 1:09 PM, Osvaldo Doederlein wrote: > Java 7 will have new syntax for literal collections, so it's a top concern > to have lambda/function type syntax that goes well with that Seeing the proposal I was thinking that the invocation syntax might integrate nicely with this. Maybe collection literals could be implemented sharing the same syntax? This would be in the spirit of the apply and update methods in Scala. I do agree with the previous post that it doesn't look quite like Java though. But I think it's mainly the types, I'd rather see ordinary parentheses used for the type syntax. +1 for having a single delimiterter between args and expr/stmts. Not necessary using ':' but the use of a only a single delimeter for parameters and expression nested in the same parenthesis/block groups the args with the expression better. IOW (int a, int b: a+b) is better than (int a, int b) :(a + b) and (:5) much better than ():(5) BR, John From reinier at zwitserloot.com Wed Mar 17 21:13:31 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Thu, 18 Mar 2010 05:13:31 +0100 Subject: Something simpler? In-Reply-To: <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> Message-ID: <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> I just don't understand how this works. Some syntax doesn't feel right to someone, and the magic words "This isn't java" are spoken. Is there some sort of device to measure this property? I'd love to get my hands on a javometer. Hm. Let me try a different direction. "I think Mark Reinhold's strawman proposal does not look like java. It violates the cardinal rule of language extension: Do no harm". Now we're even and we can throw both proposals into the dust bin and start over. Or possibly, we should say that claiming something "doesn't look like java" and "does harm" is meaningless unless its backed up with more than a gut instinct. In an attempt to follow my own advice, I'll retort one of your claims that you didn't back up: The notion that this syntax "wouldn't be understood" by a java programmer. In my defense of Peter's proposed syntax, This is the Reinhold Strawman syntax way to do it: #int() two = #()(2); and this would be the Levart Bracket syntax way: [:int] two = (:2); Both look like gobbledygook to someone not familiar with the feature, and have no clear match in existing java syntax that is somewhat similar to allow such a programmer to take an educated guess. The poor programmer is going to have to figure this out from the way they look alone. In the first case, the "#" is virtually new; the only existing java concept that involves the hash is that # is used as member delimiter in javadoc links. Closures have absolutely nothing to do with type members; in the strawman hashes are used both to identify function types and to create closures. Neither of which are type members or even roughly analogous to type members. Furthermore, the #()(2) looks kind of odd and feels like the first set of parens is optional or a mistake of some sort. In fact, if you remove all parens and hashes from the first snippet, its legal java, but not at all what was intended. (int two = 2; - no closure). In the second case, we have similar problems. There's a colon involved that's meaningless if you don't know what its for, and array brackets. Array brackets *around* something that's obviously a type is completely unknown territory, and, similar to the strawman's hash, gives the casual java programmer nothing. The one thing where existing java uses them (arrays) has nothing whatsoever to do with closures, and like the # in strawman, the placement of those braces means this syntax clearly isn't about arrays. Again, here, removing the weird symbols ([] and colons) produces legal java (int two = (2);) that isn't what was intended. The conclusion then is that you're right. It would indeed not be understood by a java programmer that has no experience with this concept. However, the same thing can be said about the strawman syntax! Thus, they both lose at this 'it feels like java' game. Given that java has absolutely no concept of closures that don't come with a ridiculous verbiage (AICs), any proposal that will fit the bill for Project Lambda will likely lose this game. If this game is to be won, start eliminating concepts. Get rid of function types - you can probably do without them. Get rid of the (for java6, at least) crazy amounts of inference, and move towards something that looks and feels a lot like CICE. Using parens instead of brackets or vice versa is not going to change the amount of new concepts a programmer needs to understand. This completely changes the direction of Lambda, but at least there'd be movement towards something a java programmer not familiar with the concept might understand just by looking at it. There's a much, much simpler alternative, though. Stop worrying about closures being so natural that any java programmer will instantly grok them even if not familiar with them, and learn to accept that this simply isn't going to happen. Instead, assume that java programmers will pick up on it, given time. They figured out generics after a while, they can handle closures: At first it looks confusing, then they learn a little about it, and they understand. It's rather freeing to do this, as now comparing proposals can be done using much more dare I say sensible requirements: - How long does it take someone entirely familiar with closures to distill the intent behind some line of code that involves closures, when looking at the line? Using the same delimiter (parens) too much is going to make it very hard to visually match braces. - How well will it integrate into existing libraries, particularly those that have had to make do with SAM types to fill their closure needs? --Reinier Zwitserloot NB: Osvaldo, your comment about polyglotters is a good one to make, but programmers who natively think in Objective C are somewhat unlikely to try out Java (and regardless, ObjC syntax is closer to smalltalk than C, so switching to java is syntaxwise going to be quite a jump anyway), and in C, the annotation concept is so different, both in semantics and usage, that I doubt much confusion will ensue. Fortunately, I doubt a polyglotter is going to weigh any confusion stemming from this problem heavier than java not having closures at all, so presumably they'd go easy on java for it. On Wed, Mar 17, 2010 at 9:10 AM, Joshua Bloch wrote: > I don't want to be the party pooper here, but this doesn't look at all like > Java. I'm afraid it violates the cardinal rule of language > extension: primum nil nocere. > > Josh > > On Tue, Mar 16, 2010 at 4:13 PM, Peter Levart >wrote: > > > In light of recent Remi Forax's plea for simpler syntax, in light of of > '#' > > and '.(' considered > > harmful, in light of Neal Gafter's blog about desirable orthogonality of > > language features: > > > > > > > http://gafter.blogspot.com/2006/09/failure-of-imagination-in-language_17.html > > > > and above all in light of Lawrence Kesteloot's writing: > > > > http://www.teamten.com/lawrence/writings/the_language_squint_test.html > > > > which extends "orthogonality" to syntax as well, here's my 3rd attempt at > a > > simpler syntax: > > > > > > FunctionType: > > '[' ParameterTypes_opt ':' ResultType Throws_opt ']' > > > > ExpressionLambda: > > '(' ParameterList_opt ':' Expression ')' > > > > StatementLambda: > > '{' ParameterList_opt ':' Statements '}' > > > > FunctionInvocationExpression: > > FunctionTypedExpression '[' ExpressionList_opt ']' > > > > > > examples: > > > > > > [:int] two = (:2); > > > > assert two[] == 2; > > > > > > [File:String throws IOException] readFile = { > > File f: > > Reader in = new FileReader(f); > > try { > > char[] buf = new char[8192]; > > StringBuilder sb = new StringBuilder(); > > int nread; > > while ((nread = in.read(buf)) >= 0) > > sb.append(buf, 0, nread); > > return sb.toString(); > > } > > finally { > > try { in.close(); } catch (IOException e) { // ignore } > > } > > }; > > > > String text = readFile[new File("/etc/passwd")]; > > > > > > [[A:R throws E], A : [:R throws E]] curry = ([A:R throws E] lambda, A arg > : > > (:lambda[arg])); > > > > [[A:R throws E], A : [:R throws E]] curry2 = { > > [A:R throws E] lambda, A arg : > > return (:lambda[arg]); > > }; > > > > [A:R throws E] lambda = { > > A a: > > if (a == null) > > throw new E(); > > return new R(a); > > }; > > > > [:R throws E] curried = curry[lambda, new A()]; > > > > R r = curried[]; > > > > > > discussion: > > > > > > I know, I know, '[]' are reserved for arrays. But so are '()' - for > > expressions, > > method/constructor params and casts. The point is that '()' are very much > > abused in current 0.15 > > lambda proposal for function types as well as lambdas (just look at > > expression lambda > > potentially containing 3 pairs of '()' in single construct). Lambda and > > function-typed heavy > > code is starting to look like Lisp - not very Java like. The point that > > Lawrance Kesteloot > > beautifully explains in his writing is that different things combined > > together should visually > > fall-apart - they should be easily decomposable into components. > > > > Since function type / array type combinations are deprecated anyway, this > > proposal steps right > > onto the syntax tokens that are traditionally reserved for arrays. It > does > > not prevent > > combinations of function types and array types but it makes the less used > > combination more > > awkward-looking to benefit other more useful combinations (like casting > to > > function types, > > specifying function-typed parameters in methods, chaining method and > > function calls). > > > > The syntax of expression lambda is similar to parenthesized expression. > It > > just adds optional > > formal parameters and a mandatory delimiter immediately after opening > '('. > > Likewise the syntax > > of statement lambda is similar to block statement. It just adds optional > > formal parameters and a > > mandatory delimiter immediately after opening '{': > > > > (12) vs. (:12) > > > > { System.out.println(); } vs . {: System.out.println(); } > > > > > > Regards, Peter > > > > > > From jjb at google.com Thu Mar 18 15:28:31 2010 From: jjb at google.com (Joshua Bloch) Date: Thu, 18 Mar 2010 15:28:31 -0700 Subject: Something simpler? In-Reply-To: <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> Message-ID: <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> Reinier, On Wed, Mar 17, 2010 at 9:13 PM, Reinier Zwitserloot < reinier at zwitserloot.com> wrote: > I just don't understand how this works. Some syntax doesn't feel right to > someone, and the magic words "This isn't java" are spoken. Is there some > sort of device to measure this property? I'd love to get my hands on a > javometer. I don't have a Javometer, but my assertion isn't arbitrary, and it isn't purely aesthetic (though it does have an aesthetic component). Looking at the proposed syntax, I can tell you why it doesn't look like Java: [:int] two = (:2); assert two[] == 2; Java declares return types *before* variables and doesn't use the colon to indicate the return type. Other languages (such as Pascal and Scala) put the types after the variable name, separated by a colon. So this is a specific point where the proposed syntax deviates from established Java norms. Also, brackets strongly suggest arrays to existing Java programmers, especially when preceded by an identifier. This is even more true if the brackets contain an integer-valued expression: assert x[i] == 42; If x[i] could be a lambda invocation as well as an array reference in the above statement, we've done real harm to the language. Josh From schulz at the-loom.de Thu Mar 18 16:09:44 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Fri, 19 Mar 2010 00:09:44 +0100 Subject: Summary: Lambda syntax In-Reply-To: <4BA0A3A3.1000108@the-loom.de> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> Message-ID: <4BA2B2B8.5060303@the-loom.de> So I summed up the proposed lambda syntaxes, hopefully picked all of them from the list. The summary is below, and the nicer to read document version is as before at the following URL: http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm In case of mistakes or missed proposals, let me know. Cheers, Stefan 0. Common syntax Block: { BlockStatements } BlockStatements: BlockStatement BlockStatements BlockStatement BlockStatement: LocalVariableDeclarationStatement ClassDeclaration Statement ParameterList: Parameter Parameter, ParameterList Parameter: Type Identifier 1. Straw-man, latest Proposes two lambda definitions: lambda expressions and statements. Return type is inferred and throws meant to be transparent. LambdaExpression: # ( ParameterListopt ) ( Expression ) # ( ParameterListopt ) Block Examples: #() ( 7 ); #(Event e) { handle(e); } #(File f) { return f.getName(); }; #(#R(A)(throws E) l, A a) ( #() ( l.(a) ) ); 2. R?my Forax, 05 Jan 2010 Proposes to use a keyword lambda instead of #. LambdaExpression: lambda ( ParameterListopt ) ( Expression ) lambda ( ParameterListopt ) Block Examples: lambda() ( 7 ); lambda(Event e) { handle(e); }; lambda(File f) { return f.getName(); }; lambda(#R(A)(throws E) l, A a) ( lambda() ( l.(a) ) ); 3. Peter Levart, 26 Jan 2010 LambdaExpression: # ( ParametersListopt ResultParameteropt ) Block ResultParameter: : Parameter Examples: #(: int i) { i = 7 }; #(Event e) { handle(e); }; #(File f : String s) { s = f.getName(); }; #(#(A: R throws E) l, A a : #(: R throws E) c) { c = #(: R r) { r = l.(a); }; }; 4. Peter Levart, 1 Feb 2010 LambdaExpression: # ( ParameterListopt -> ReturnTypeopt ) Block Examples: #(->int) { return 7; }; #(Event e -> void) { handle(e); }; #(File f -> String) { return f.getName(); }; #(#(A -> R throws E) l, A a -> #(-> R throws E)) { return #(->R) { return l.(a); }; }; 5. Neal Gafter, 9 Feb 2010 LambdaExpression: ( ParameterListopt ) -> Expression ( ParameterListopt ) -> Block Examples: () -> 7; (Event e) -> { handle(e); }; (File f) -> { return f.getName(); }; ((A) -> R throws E l, A a) -> () -> l.(a); 6. BGGA LambdaExpression: { ParameterListopt => BlockStatementsopt Expressionopt } Examples: { => 7 } { Event e => handle(e); }; { File f => f.getName() }; { { A => R throws E } l, A a => { => l.(a) } }; 7. Peter Levart, 2 Mar 2010 LambdaExpression: ( ParameterListopt -> BlockStatementsopt Expression ) Examples: ( -> 7 ); ( Event e -> handle(e); void }; ( File f -> f.getName() ); ( (A -> R throws E ) l, A a -> ( -> l.(a) ) ); 8. Howard Lovatt, 11 Mar 2010 LambdaExpression: new #< Signature > ( BlockStatementsopt Expression ) Signature: ReturnType ( ParameterListopt ) Throwsopt Examples: new #< int() > (7); new #< void(Event e) > (handle(e); null); new #< String(File f) > (f.getName()); #< #< R() throws E >( #< R( A ) throws E > l, A a ) > ( new #< R() throws E >()( l.( a ) ); 9. C++ (via Stephen Colebourne), 14 Mar 2010 (translated to lambda-use) LambdaExpression: [ Accessorsopt ] ParameterDeclopt ReturnTypeDeclopt { BlockStatementsopt } ParameterDecl: ( ParameterList ) ReturnTypeDecl: -> ReturnType Accessors: & = Closings Closings: Closing Closing, Closings Closing: & Identifier Identifier this Examples: [] { return 7; }; [] (Event e) { handle(e); }; [] (File f) { return file.getName(); }; [] (R (*l)(A), A a) { return []{ return l.(a); }; 10. R?mi Forax, 14 Mar 2010 LambdaExpression: ( ParameterListopt ) ( Expression ) ( ParameterListopt ) Block Examples: () ( 7 ); (Event e) { handle(e); } (File f) { return f.getName(); }; (R(A)(throws E) l, A a) ( () ( l.(a) ) ); 11. Peter Levart, 17 Mar 2010 LambdaExpression: ( ParameterListopt : Expression ) { ParameterListopt : BlockStatements } FunctionInvocationExpression: FunctionTypedExpression [ ExpressionListopt ] Examples: (:7); { Event e : handle(e); }; { File f : return f.getName(); }; ( [ A : R throws E ] l, A a : (: l[a]) ); From alex.blewitt at gmail.com Thu Mar 18 17:04:08 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Fri, 19 Mar 2010 00:04:08 +0000 Subject: Summary: Lambda syntax In-Reply-To: <4BA2B2B8.5060303@the-loom.de> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> Message-ID: <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> Good work. There are inconsistencies in 7, 16 and 17. One is missing a "throws", one declares that it uses PipedException but then uses commas, and one has another error I have forgotten (another missing throws?) In addition, the example with "new" probably shouldn't be included, since it's not valid for all lambdas, regardless of the syntax used for representing the lambdas themselves. Alex Sent from my (new) iPhone On 18 Mar 2010, at 23:09, Stefan Schulz wrote: > So I summed up the proposed lambda syntaxes, hopefully picked all of > them from the list. The summary is below, and the nicer to read > document > version is as before at the following URL: > http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm > > In case of mistakes or missed proposals, let me know. > > Cheers, > Stefan > > > 0. Common syntax > Block: > { BlockStatements } > > BlockStatements: > BlockStatement > BlockStatements BlockStatement > > BlockStatement: > LocalVariableDeclarationStatement > ClassDeclaration > Statement > > ParameterList: > Parameter > Parameter, ParameterList > > Parameter: > Type Identifier > > 1. Straw-man, latest > Proposes two lambda definitions: lambda expressions and statements. > Return type is inferred and throws meant to be transparent. > > LambdaExpression: > # ( ParameterListopt ) ( Expression ) > # ( ParameterListopt ) Block > > Examples: > #() ( 7 ); > #(Event e) { handle(e); } > #(File f) { return f.getName(); }; > #(#R(A)(throws E) l, A a) ( #() ( l.(a) ) ); > > > 2. R?my Forax, 05 Jan 2010 > Proposes to use a keyword lambda instead of #. > > LambdaExpression: > lambda ( ParameterListopt ) ( Expression ) > lambda ( ParameterListopt ) Block > > Examples: > lambda() ( 7 ); > lambda(Event e) { handle(e); }; > lambda(File f) { return f.getName(); }; > lambda(#R(A)(throws E) l, A a) ( lambda() ( l.(a) ) ); > > 3. Peter Levart, 26 Jan 2010 > LambdaExpression: > # ( ParametersListopt ResultParameteropt ) Block > > ResultParameter: > : Parameter > > Examples: > #(: int i) { i = 7 }; > #(Event e) { handle(e); }; > #(File f : String s) { s = f.getName(); }; > #(#(A: R throws E) l, A a : #(: R throws E) c) { c = #(: R r) { r = > l.(a); }; }; > > 4. Peter Levart, 1 Feb 2010 > LambdaExpression: > # ( ParameterListopt -> ReturnTypeopt ) Block > > Examples: > #(->int) { return 7; }; > #(Event e -> void) { handle(e); }; > #(File f -> String) { return f.getName(); }; > #(#(A -> R throws E) l, A a > -> #(-> R throws E)) { return #(->R) { return l.(a); }; }; > > 5. Neal Gafter, 9 Feb 2010 > LambdaExpression: > ( ParameterListopt ) -> Expression > ( ParameterListopt ) -> Block > > Examples: > () -> 7; > (Event e) -> { handle(e); }; > (File f) -> { return f.getName(); }; > ((A) -> R throws E l, A a) -> () -> l.(a); > > 6. BGGA > LambdaExpression: > { ParameterListopt => BlockStatementsopt Expressionopt } > > Examples: > { => 7 } > { Event e => handle(e); }; > { File f => f.getName() }; > { { A => R throws E } l, A a => { => l.(a) } }; > > 7. Peter Levart, 2 Mar 2010 > LambdaExpression: > ( ParameterListopt -> BlockStatementsopt Expression ) > > Examples: > ( -> 7 ); > ( Event e -> handle(e); void }; > ( File f -> f.getName() ); > ( (A -> R throws E ) l, A a -> ( -> l.(a) ) ); > > 8. Howard Lovatt, 11 Mar 2010 > LambdaExpression: > new #< Signature > ( BlockStatementsopt Expression ) > Signature: > ReturnType ( ParameterListopt ) Throwsopt > > Examples: > new #< int() > (7); > new #< void(Event e) > (handle(e); null); > new #< String(File f) > (f.getName()); > #< #< R() throws E >( #< R( A ) throws E > l, A a ) > > ( new #< R() throws E >()( l.( a ) ); > > 9. C++ (via Stephen Colebourne), 14 Mar 2010 > (translated to lambda-use) > > LambdaExpression: > [ Accessorsopt ] ParameterDeclopt ReturnTypeDeclopt { > BlockStatementsopt } > > ParameterDecl: > ( ParameterList ) > > ReturnTypeDecl: > -> ReturnType > > Accessors: > & > = > Closings > > Closings: > Closing > Closing, Closings > > Closing: > & Identifier > Identifier > this > > Examples: > [] { return 7; }; > [] (Event e) { handle(e); }; > [] (File f) { return file.getName(); }; > [] (R (*l)(A), A a) { return []{ return l.(a); }; > > 10. R?mi Forax, 14 Mar 2010 > LambdaExpression: > ( ParameterListopt ) ( Expression ) > ( ParameterListopt ) Block > > Examples: > () ( 7 ); > (Event e) { handle(e); } > (File f) { return f.getName(); }; > (R(A)(throws E) l, A a) ( () ( l.(a) ) ); > > 11. Peter Levart, 17 Mar 2010 > LambdaExpression: > ( ParameterListopt : Expression ) > { ParameterListopt : BlockStatements } > > FunctionInvocationExpression: > FunctionTypedExpression [ ExpressionListopt ] > > Examples: > (:7); > { Event e : handle(e); }; > { File f : return f.getName(); }; > ( [ A : R throws E ] l, A a : (: l[a]) ); > > > From collin.fagan at gmail.com Thu Mar 18 18:09:35 2010 From: collin.fagan at gmail.com (Collin Fagan) Date: Thu, 18 Mar 2010 20:09:35 -0500 Subject: Summary: Lambda syntax In-Reply-To: <4BA2B2B8.5060303@the-loom.de> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> Message-ID: Hi Stefan, I was trying to get a little feedback on some of my ideas but I guess it got missed. Can we use : in the lambda syntax? Off the top of my head I think it's only used in the for-each loop and the ternary operator. If : is up for grabs then my next question is: can we infix this operator instead of prefixing it? Examples: (borrowed from an earlier post by R?mi Forax) A function that takes an int and returns an int: int(int) becomes int:(int) and ... A function that takes an int and returns nothing: void:(int) A function that takes two ints and returns an int: int:(int, int) A function that throws an Exception: int:(int) throws Exception A function that takes a function that throws an Exception: int:(int:(int) throws Exception) Grammar: ResultType :( TypeList ) throws ExceptionList This syntax reads left to right in a way that is similar to method signatures, with the method name replaced by a ':' . Now when we get to the curry examples I would like to customize the assignment operator. Since I chose ':' how about using ':=' as the "curry operator" ? Examples: (borrowed from an earlier post by Bob Foster) class A { void foo(int x) { ... } void :(int) fun = { ... } } // curry examples A a = new A(); void:() f1 := a.foo(2); void:() f2 := a.foo(); void:() f3 := A.fun(2); Finally, to stay with the theme, invoking a lambda would use '::' f1::(); f2::(); f3::(); Optionally this syntax could be: f1.:(); or f1:.(); but I found neither of those particularly compelling. I *think* the : is no harder to type then the #. (At least on the English keyboards I'm used to.) The := construct is used in other languages (like Pascal, Eiffel and Smalltalk) but admittedly not for curring. The :: construct is used in C++, but again, not in the way I plan on using it. I could continue to flesh this out into a real proposal if people found the syntax compelling. If I've committed any egregious sin in my post I apologize. Thank you, - Collin On Thu, Mar 18, 2010 at 6:09 PM, Stefan Schulz wrote: > So I summed up the proposed lambda syntaxes, hopefully picked all of > them from the list. The summary is below, and the nicer to read document > version is as before at the following URL: > ? http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm > > In case of mistakes or missed proposals, let me know. > > Cheers, > Stefan > > > 0. Common syntax > Block: > ? ? { BlockStatements } > > BlockStatements: > ? ? BlockStatement > ? ? BlockStatements BlockStatement > > BlockStatement: > ? ? LocalVariableDeclarationStatement > ? ? ClassDeclaration > ? ? Statement > > ParameterList: > ? ? Parameter > ? ? Parameter, ParameterList > > Parameter: > ? ? Type Identifier > > 1. Straw-man, latest > Proposes two lambda definitions: lambda expressions and statements. > Return type is inferred and throws meant to be transparent. > > LambdaExpression: > ? ? # ( ParameterListopt ) ( Expression ) > ? ? # ( ParameterListopt ) Block > > Examples: > #() ( 7 ); > #(Event e) { handle(e); } > #(File f) { return f.getName(); }; > #(#R(A)(throws E) l, A a) ( #() ( l.(a) ) ); > > > 2. R?my Forax, 05 Jan 2010 > Proposes to use a keyword lambda instead of #. > > LambdaExpression: > ? ? lambda ( ParameterListopt ) ( Expression ) > ? ? lambda ( ParameterListopt ) Block > > Examples: > lambda() ( 7 ); > lambda(Event e) { handle(e); }; > lambda(File f) { return f.getName(); }; > lambda(#R(A)(throws E) l, A a) ( lambda() ( l.(a) ) ); > > 3. Peter Levart, 26 Jan 2010 > LambdaExpression: > ? ? # ( ParametersListopt ResultParameteropt ) Block > > ResultParameter: > ? ? : Parameter > > Examples: > #(: int i) { i = 7 }; > #(Event e) { handle(e); }; > #(File f : String s) { s = f.getName(); }; > #(#(A: R throws E) l, A a : #(: R throws E) c) { c = #(: R r) { r = > l.(a); }; }; > > 4. Peter Levart, 1 Feb 2010 > LambdaExpression: > ? ? # ( ParameterListopt -> ReturnTypeopt ) Block > > Examples: > #(->int) { return 7; }; > #(Event e -> void) { handle(e); }; > #(File f -> String) { return f.getName(); }; > #(#(A -> R throws E) l, A a > ? -> #(-> R throws E)) { return #(->R) { return l.(a); }; }; > > 5. Neal Gafter, 9 Feb 2010 > LambdaExpression: > ? ? ( ParameterListopt ) -> Expression > ? ? ( ParameterListopt ) -> Block > > Examples: > () -> 7; > (Event e) -> { handle(e); }; > (File f) -> { return f.getName(); }; > ((A) -> R throws E l, A a) -> () -> l.(a); > > 6. BGGA > LambdaExpression: > ? ? { ParameterListopt => BlockStatementsopt Expressionopt } > > Examples: > { => 7 } > { Event e => handle(e); }; > { File f => f.getName() }; > { { A => R throws E } l, A a => { => l.(a) } }; > > 7. Peter Levart, 2 Mar 2010 > LambdaExpression: > ? ? ( ParameterListopt -> BlockStatementsopt Expression ) > > Examples: > ( -> 7 ); > ( Event e -> handle(e); void }; > ( File f -> f.getName() ); > ( (A -> R throws E ) l, A a -> ( -> l.(a) ) ); > > 8. Howard Lovatt, 11 Mar 2010 > LambdaExpression: > ? ? new #< Signature > ( BlockStatementsopt Expression ) > Signature: > ? ? ReturnType ( ParameterListopt ) Throwsopt > > Examples: > new #< int() > (7); > new #< void(Event e) > (handle(e); null); > new #< String(File f) > (f.getName()); > #< #< R() throws E >( #< R( A ) throws E > l, A a ) > > ? ( new #< R() throws E >()( l.( a ) ); > > 9. C++ (via Stephen Colebourne), 14 Mar 2010 > (translated to lambda-use) > > LambdaExpression: > ? ? [ Accessorsopt ] ParameterDeclopt ReturnTypeDeclopt { > BlockStatementsopt } > > ParameterDecl: > ? ? ( ParameterList ) > > ReturnTypeDecl: > ? ? -> ReturnType > > Accessors: > ? ? & > ? ? = > ? ? Closings > > Closings: > ? ? Closing > ? ? Closing, Closings > > Closing: > ? ? & Identifier > ? ? Identifier > ? ? this > > Examples: > [] { return 7; }; > [] (Event e) { handle(e); }; > [] (File f) { return file.getName(); }; > [] (R (*l)(A), A a) { return []{ return l.(a); }; > > 10. R?mi Forax, 14 Mar 2010 > LambdaExpression: > ? ? ( ParameterListopt ) ( Expression ) > ? ? ( ParameterListopt ) Block > > Examples: > () ( 7 ); > (Event e) { handle(e); } > (File f) { return f.getName(); }; > (R(A)(throws E) l, A a) ( () ( l.(a) ) ); > > 11. Peter Levart, 17 Mar 2010 > LambdaExpression: > ? ? ( ParameterListopt : Expression ) > ? ? { ParameterListopt : BlockStatements } > > FunctionInvocationExpression: > ? ? FunctionTypedExpression [ ExpressionListopt ] > > Examples: > (:7); > { Event e : handle(e); }; > { File f : return f.getName(); }; > ( [ A : R throws E ] l, A a : (: l[a]) ); > > > > From reinier at zwitserloot.com Thu Mar 18 18:48:41 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 19 Mar 2010 02:48:41 +0100 Subject: Something simpler? In-Reply-To: <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> Message-ID: <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> But "#", from its javadoc roots, suggests type member, which is just as completely off base as [] suggesting array access. If we want lean syntax I think overloading the semantic meaning of a few symbols is inevitable. It would be good if we picked symbols that read naturally yet don't have too many commonly used meanings in today's java, and with arrays moving ever further towards the background, [] is a fair suggestion. FWIW, I would prefer it if closure invoke remained .(), because unlike any of the other usage of [] in the Levart Bracket proposal, that *can* be mistaken for array deref. Then again, there's a coin proposal that was taken quite seriously which aims to introduce operator overloading to java and make expressionA[expressionB] mean: Check if expressionA implements ListAddressable, and if so, compile this expression as if it read expressionA.get(expressionB). The theory here is presumably that doing an indexed retrieval on a list-like object is sufficiently similar to an array access that using brackets is acceptable. But that's not the end of that particular line of thought - you end up with the conclusion that calling a method that takes 1 integer and returns something is theoretically retrofittable as 'list-like' and as there are plenty of concepts that aren't really implemented as physical list-like constructions that nevertheless could and probably will end up as such ListAddressable instances (such as e.g range(10,1000)), we must conclude that in fact any method call is sufficiently similar to arrays, so that if this ListAccessible proposal is acceptable, then brackets are acceptable for methods. And if method calls are sufficiently similar to array access, then so is closure invocation. There's also the idea of allowing [] or {} to be used for collection literals. {} in java right now means "block" or "body" and nothing else. It has nothing to do with maps or even literals. Your same argument would apply there. Why is this the first time you're complaining about '[', ']', '{' and '}' being used for things that don't mean what they do in Java6? If anything this proposal should receive _more_ leniency than the others, because its already so complicated in other areas, too. Just playing advocate of the devil. Personal vote: Go with .() instead, and the reasoned argument behind it is this: [] is for arrays and not for anything else. Don't introduce [] access for Lists either*. *) Or, tilt the other way and go whole hog with operator overloading. Consistency is worth something. --Reinier Zwitserloot On Thu, Mar 18, 2010 at 11:28 PM, Joshua Bloch wrote: > Reinier, > > On Wed, Mar 17, 2010 at 9:13 PM, Reinier Zwitserloot < > reinier at zwitserloot.com> wrote: > >> I just don't understand how this works. Some syntax doesn't feel right to >> someone, and the magic words "This isn't java" are spoken. Is there some >> sort of device to measure this property? I'd love to get my hands on a >> javometer. > > > I don't have a Javometer, but my assertion isn't arbitrary, and it isn't > purely aesthetic (though it does have an aesthetic component). Looking at > the proposed syntax, I can tell you why it doesn't look like Java: > > [:int] two = (:2); > assert two[] == 2; > > > Java declares return types *before* variables and doesn't use the colon > to indicate the return type. Other languages (such as Pascal and Scala) put > the types after the variable name, separated by a colon. So this is a > specific point where the proposed syntax deviates from established Java > norms. > > Also, brackets strongly suggest arrays to existing Java programmers, > especially when preceded by an identifier. This is even more true if the > brackets contain an integer-valued expression: > > assert x[i] == 42; > > If x[i] could be a lambda invocation as well as an array reference in the > above statement, we've done real harm to the language. > > Josh > From jkuhnert at gmail.com Thu Mar 18 19:05:58 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Thu, 18 Mar 2010 22:05:58 -0400 Subject: Summary: Lambda syntax In-Reply-To: References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> Message-ID: <7926817e1003181905p65ba51e5ga0e2961f198d2179@mail.gmail.com> Going off the list I'd put this one up with #s 5 and 1 as far as being easy on the eyes and something that feels like it fits goes. Assuming there aren't any technical dragons lurking in the details. On Thursday, March 18, 2010, Collin Fagan wrote: > Hi Stefan, > > I was trying to get a little feedback on some of my ideas but I guess > it got missed. > > Can we use : in the lambda syntax? Off the top of my head I think it's > only used in the for-each loop and the ternary operator. > > If : is up for grabs then my next question is: can we infix this > operator instead of prefixing it? > > Examples: (borrowed from an earlier post by R?mi Forax) > > A function that takes an int and returns an int: > > int(int) > > becomes > > int:(int) > > and ... > > A function that takes an int and returns nothing: > void:(int) > > A function that takes two ints and returns an int: > int:(int, int) > > A function that throws an Exception: > int:(int) throws Exception > > A function that takes a function that throws an Exception: > int:(int:(int) throws Exception) > > Grammar: > ResultType :( TypeList ) throws ExceptionList > > This syntax reads left to right in a way that is similar to method > signatures, with the method name replaced by a ':' . > > Now when we get to the curry examples I would like to customize the > assignment operator. Since I chose ':' how about using ':=' ? as the > "curry operator" ? > > Examples: (borrowed from an earlier post by Bob Foster) > > class A { > ?void foo(int x) { ... } > ?void :(int) fun = { ... } > } > > // curry examples > A a = new A(); > void:() f1 := a.foo(2); > void:() f2 := a.foo(); > void:() f3 := A.fun(2); > > Finally, to stay with the theme, invoking a lambda would use '::' > > f1::(); > f2::(); > f3::(); > > Optionally this syntax could be: f1.:(); or f1:.(); but I found > neither of those particularly compelling. > > I *think* the : is no harder to type then the #. (At least on the > English keyboards I'm used to.) > The := construct is used in other languages (like Pascal, Eiffel and > Smalltalk) but admittedly not for curring. > The :: construct is used in C++, but again, not in the way I plan on using it. > > I could continue to flesh this out into a real proposal if people > found the syntax compelling. If I've committed any egregious sin in my > post I apologize. > > Thank you, > > - Collin > > On Thu, Mar 18, 2010 at 6:09 PM, Stefan Schulz wrote: >> So I summed up the proposed lambda syntaxes, hopefully picked all of >> them from the list. The summary is below, and the nicer to read document >> version is as before at the following URL: >> ? Lambda Syntaxes? >> >> In case of mistakes or missed proposals, let me know. >> >> Cheers, >> Stefan >> >> >> 0. Common syntax >> Block: >> ? ? { BlockStatements } >> >> BlockStatements: >> ? ? BlockStatement >> ? ? BlockStatements BlockStatement >> >> BlockStatement: >> ? ? LocalVariableDeclarationStatement >> ? ? ClassDeclaration >> ? ? Statement >> >> ParameterList: >> ? ? Parameter >> ? ? Parameter, ParameterList >> >> Parameter: >> ? ? Type Identifier >> >> 1. Straw-man, latest >> Proposes two lambda definitions: lambda expressions and statements. >> Return type is inferred and throws meant to be transparent. >> >> LambdaExpression: >> ? ? # ( ParameterListopt ) ( Expression ) >> ? ? # ( ParameterListopt ) Block >> >> Examples: >> #() ( 7 ); >> #(Event e) { handle(e); } >> #(File f) { return f.getName(); }; >> #(#R(A)(throws E) l, A a) ( #() ( l.(a) ) ); >> >> >> 2. R?my Forax, 05 Jan 2010 >> Proposes to use a keyword lambda instead of #. >> >> LambdaExpression: >> ? ? lambda ( ParameterListopt ) ( Expression ) >> ? ? lambda ( ParameterListopt ) Block >> >> Examples: >> lambda() ( 7 ); >> lambda(Event e) { handle(e); }; >> lambda(File f) { return f.getName(); }; >> lambda(#R(A)(throws E) l, A a) ( lambda() ( l.(a) ) ); >> >> 3. Peter Levart, 26 Jan 2010 >> LambdaExpression: >> ? ? # ( ParametersListopt ResultParameteropt ) Block >> >> ResultParameter: >> ? ? : Parameter >> >> Examples: >> #(: int i) { i = 7 }; >> #(Event e) { handle(e); }; >> #(File f : String s) { s = f.getName(); }; >> #(#(A: R throws E) l, A a : #(: R throws E) c) { c = #(: R r) { r = >> l.(a); }; }; >> >> 4. Peter Levart, 1 Feb 2010 >> LambdaExpression: >> ? ? # ( ParameterListopt -> ReturnTypeopt ) Block >> >> Examples: >> #(->int) { return 7; }; >> #(Event e -> void) { handle(e); }; >> #(File f -> String) { return f.getName(); }; >> #(#(A -> R throws E) l, A a >> ? -> #(-> R throws E)) { return #(->R) { return l.(a); }; }; >> >> 5. Neal Gafter, 9 Feb 2010 >> LambdaExpression: >> ? ? ( ParameterListopt ) -> Expression >> ? ? ( ParameterListopt ) -> Block >> >> Examples: >> () -> 7; >> (Event e) -> { handle(e); }; >> (File f) -> { return f.getName(); }; >> ((A) -> R throws E l, A a) -> () -> l.(a); >> >> 6. BGGA >> LambdaExpression: >> ? ? { ParameterListopt => BlockStatementsopt Expressionopt } >> >> Examples: >> { => 7 } >> { Event e => handle(e); }; >> { File f => f.getName() }; >> { { A => R throws E } l, A a => { => l.(a) } }; >> >> 7. Peter Levart, 2 Mar 2010 >> LambdaExpression: >> ? ? ( ParameterListopt -> BlockStatementsopt Expression ) >> >> Examples: >> ( -> 7 ); >> ( Event e -> handle(e); void }; >> ( File f -> f.getName() ); >> ( (A -> R throws E ) l, A a -> ( -> l.(a) ) ); >> >> 8. Howard Lovatt, 11 Mar 2010 >> LambdaExpression: >> ? ? new #< Signature > ( BlockStatementsopt Expression ) >> Signature: >> ? ? ReturnType ( ParameterListopt ) Throwsopt >> >> Examples: >> new #< int() > (7); >> new #< void(Event e) > (handle(e); null); >> new #< String(File f) > (f.getName()); >> #< #< R() throws E >( #< R( A ) throws E > l, A a ) > >> ? ( new #< R() throws E >()( l.( a ) ); >> >> 9. C++ (via Stephen Colebourne), 14 Mar 2010 >> (translated to lambda-use) >> >> LambdaExpression: >> From Liam.Knox at morganstanley.com Thu Mar 18 19:16:19 2010 From: Liam.Knox at morganstanley.com (Knox, Liam) Date: Fri, 19 Mar 2010 11:16:19 +0900 Subject: Something simpler? In-Reply-To: <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com><17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com><560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com><17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> Message-ID: <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> # - used already in java doc [] - used already in java code Being ambiguous in the Java Syntax seems much more concerning to me in these proposals Being only a 'java programmer', I would not be happy with a syntax that introduces ambiguity in reading the code within a source file {} as blocks and () for parameter definitions are very bread and butter in the understanding of all Java programmers readability vs. functionality needs to be weighed up, as with Generics, for all their good, they did add a fair amount of readability complexity Two cents worth [:int] two = (:2); assert two[] == 2; Does not look like something simpler, and personally doesn't feel like Java -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Reinier Zwitserloot Sent: Friday, March 19, 2010 10:49 AM To: Joshua Bloch Cc: lambda-dev Subject: Re: Something simpler? But "#", from its javadoc roots, suggests type member, which is just as completely off base as [] suggesting array access. If we want lean syntax I think overloading the semantic meaning of a few symbols is inevitable. It would be good if we picked symbols that read naturally yet don't have too many commonly used meanings in today's java, and with arrays moving ever further towards the background, [] is a fair suggestion. FWIW, I would prefer it if closure invoke remained .(), because unlike any of the other usage of [] in the Levart Bracket proposal, that *can* be mistaken for array deref. Then again, there's a coin proposal that was taken quite seriously which aims to introduce operator overloading to java and make expressionA[expressionB] mean: Check if expressionA implements ListAddressable, and if so, compile this expression as if it read expressionA.get(expressionB). The theory here is presumably that doing an indexed retrieval on a list-like object is sufficiently similar to an array access that using brackets is acceptable. But that's not the end of that particular line of thought - you end up with the conclusion that calling a method that takes 1 integer and returns something is theoretically retrofittable as 'list-like' and as there are plenty of concepts that aren't really implemented as physical list-like constructions that nevertheless could and probably will end up as such ListAddressable instances (such as e.g range(10,1000)), we must conclude that in fact any method call is sufficiently similar to arrays, so that if this ListAccessible proposal is acceptable, then brackets are acceptable for methods. And if method calls are sufficiently similar to array access, then so is closure invocation. There's also the idea of allowing [] or {} to be used for collection literals. {} in java right now means "block" or "body" and nothing else. It has nothing to do with maps or even literals. Your same argument would apply there. Why is this the first time you're complaining about '[', ']', '{' and '}' being used for things that don't mean what they do in Java6? If anything this proposal should receive _more_ leniency than the others, because its already so complicated in other areas, too. Just playing advocate of the devil. Personal vote: Go with .() instead, and the reasoned argument behind it is this: [] is for arrays and not for anything else. Don't introduce [] access for Lists either*. *) Or, tilt the other way and go whole hog with operator overloading. Consistency is worth something. --Reinier Zwitserloot On Thu, Mar 18, 2010 at 11:28 PM, Joshua Bloch wrote: > Reinier, > > On Wed, Mar 17, 2010 at 9:13 PM, Reinier Zwitserloot < > reinier at zwitserloot.com> wrote: > >> I just don't understand how this works. Some syntax doesn't feel >> right to someone, and the magic words "This isn't java" are spoken. >> Is there some sort of device to measure this property? I'd love to >> get my hands on a javometer. > > > I don't have a Javometer, but my assertion isn't arbitrary, and it > isn't purely aesthetic (though it does have an aesthetic component). > Looking at the proposed syntax, I can tell you why it doesn't look like Java: > > [:int] two = (:2); > assert two[] == 2; > > > Java declares return types *before* variables and doesn't use the > colon to indicate the return type. Other languages (such as Pascal and > Scala) put the types after the variable name, separated by a colon. So > this is a specific point where the proposed syntax deviates from > established Java norms. > > Also, brackets strongly suggest arrays to existing Java programmers, > especially when preceded by an identifier. This is even more true if > the brackets contain an integer-valued expression: > > assert x[i] == 42; > > If x[i] could be a lambda invocation as well as an array reference in > the above statement, we've done real harm to the language. > > Josh > -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law. From howard.lovatt at gmail.com Thu Mar 18 19:30:45 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 19 Mar 2010 13:30:45 +1100 Subject: Summary: Lambda syntax Message-ID: <3dd3f56a1003181930i14212e80kba31e4d48ef3b48@mail.gmail.com> Hi Stefan, Great summary of the various syntaxes. For my proposal, your B8, I think a description that fits my 'intent' is: Proposes two lambda definitions: lambda expressions and statements. Types are optionally inferred by the diamond operator. LambdaExpression: new # < *TypeList* ( *ParameterList*opt ) *Exceptions*opt > ( Expression ) new # < *TypeList* ( *ParameterList*opt ) *Exceptions*opt > Block new # < *IdentifierList*opt > ( Expression ) new # < *IdentifierList*opt > Block *IdentifierList*: *Identifier** ** Identifier, **IdentifierList * Examples: new #< int() > (7); new #< void(Event e) > { handle(e); }; new #< String(File f) > { return f.getName(); }; new #< #< R() throws E >( #< R( A ) throws E > l, A a ) > ( new #< R() throws E >()( l.( a ) ); new #<> ( 7 ); new # { handle(e); } new # { return f.getName(); }; new # ( new #<> ( l.(a) ) ); I carefully said 'intent' above, since my original post was just a quick email and not a formal specification (therefore your description was correct!). The reason for including the diamond operator, is like the rest of the proposal, for consistency with the rest of the language. It would be very odd if diamond were used for type inference for generics and a different mechanism for lambdas. Note: the use of diamond follows on for the argument for diamond itself; the argument for diamond is that it is consistent with the current generic inference for methods. I also assume that the diamond operator would be equally as applicable to Gernot Neppert's, A14, variation (which is absent from section B). In the examples, section A, how about arrays, e.g.: #[] and section B: new #[] new #<>[] Excellent summary, -- Howard. From howard.lovatt at gmail.com Thu Mar 18 19:41:42 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 19 Mar 2010 13:41:42 +1100 Subject: Summary: Lambda syntax Message-ID: <3dd3f56a1003181941k595895fau7c7f2f3cc3f8b853@mail.gmail.com> Alex, In my proposal I am specifically saying that it is up to the JVM to eliminate the new and not the compiler, therefore new valid in proposal. Just like the new could be eliminated by the JVM from: for ( final int[] row : matrix ) { result.add( filter( row, new Callable1() { public Boolean call( final Integer x ) { return x % 2 == 0; } } ); } -- Howard. From collin.fagan at gmail.com Thu Mar 18 20:30:54 2010 From: collin.fagan at gmail.com (Collin Fagan) Date: Thu, 18 Mar 2010 22:30:54 -0500 Subject: Summary: Lambda syntax In-Reply-To: <7926817e1003181905p65ba51e5ga0e2961f198d2179@mail.gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> <7926817e1003181905p65ba51e5ga0e2961f198d2179@mail.gmail.com> Message-ID: Thank you Jesse. I went ahead and copied the examples Peter Levart used for his latest proposal. FunctionType: ResultType ':('ParameterTypes_opt ')' Throws_opt ExpressionLambda: ':(' ParameterList_opt ')' '(' Expression ')' StatementLambda: ':(' ParameterList_opt ')' '{' Statements '}' FunctionInvocationExpression: FunctionTypedExpression '::(' ExpressionList_opt ')' int:() two = (2); assert two::() == 2; String :(File) throws IOException readFile = :(File f){ Reader in = new FileReader(f); try { char[] buf = new char[8192]; StringBuilder sb = new StringBuilder(); int nread; while ((nread = in.read(buf)) >= 0) sb.append(buf, 0, nread); return sb.toString(); } finally { try { in.close(); } catch (IOException e) { // ignore } } } String text = readFile::(new File("/etc/passwd")); R:() throws E :(R:(A) throws E) := :(R:(A) throws E lambda, A arg){ return lambda::(arg)); }; R:(A) throws E lambda = :(A a){ if (a == null) throw new E(); return new R(a); }; R:() throws E curried := lambda:(new A()); R r = curried::(); On Thu, Mar 18, 2010 at 9:05 PM, Jesse Kuhnert wrote: > Going off the list I'd put this one up with #s 5 and 1 as far as being > easy on the eyes and something that feels like it fits goes. Assuming > there aren't any technical dragons lurking in the details. > > On Thursday, March 18, 2010, Collin Fagan wrote: >> Hi Stefan, >> >> I was trying to get a little feedback on some of my ideas but I guess >> it got missed. >> >> Can we use : in the lambda syntax? Off the top of my head I think it's >> only used in the for-each loop and the ternary operator. >> >> If : is up for grabs then my next question is: can we infix this >> operator instead of prefixing it? >> >> Examples: (borrowed from an earlier post by R?mi Forax) >> >> A function that takes an int and returns an int: >> >> int(int) >> >> becomes >> >> int:(int) >> >> and ... >> >> A function that takes an int and returns nothing: >> void:(int) >> >> A function that takes two ints and returns an int: >> int:(int, int) >> >> A function that throws an Exception: >> int:(int) throws Exception >> >> A function that takes a function that throws an Exception: >> int:(int:(int) throws Exception) >> >> Grammar: >> ResultType :( TypeList ) throws ExceptionList >> >> This syntax reads left to right in a way that is similar to method >> signatures, with the method name replaced by a ':' . >> >> Now when we get to the curry examples I would like to customize the >> assignment operator. Since I chose ':' how about using ':=' ? as the >> "curry operator" ? >> >> Examples: (borrowed from an earlier post by Bob Foster) >> >> class A { >> ?void foo(int x) { ... } >> ?void :(int) fun = { ... } >> } >> >> // curry examples >> A a = new A(); >> void:() f1 := a.foo(2); >> void:() f2 := a.foo(); >> void:() f3 := A.fun(2); >> >> Finally, to stay with the theme, invoking a lambda would use '::' >> >> f1::(); >> f2::(); >> f3::(); >> >> Optionally this syntax could be: f1.:(); or f1:.(); but I found >> neither of those particularly compelling. >> >> I *think* the : is no harder to type then the #. (At least on the >> English keyboards I'm used to.) >> The := construct is used in other languages (like Pascal, Eiffel and >> Smalltalk) but admittedly not for curring. >> The :: construct is used in C++, but again, not in the way I plan on using it. >> >> I could continue to flesh this out into a real proposal if people >> found the syntax compelling. If I've committed any egregious sin in my >> post I apologize. >> >> Thank you, >> >> - Collin >> >> On Thu, Mar 18, 2010 at 6:09 PM, Stefan Schulz wrote: >>> So I summed up the proposed lambda syntaxes, hopefully picked all of >>> them from the list. The summary is below, and the nicer to read document >>> version is as before at the following URL: >>> ? Lambda Syntaxes? >>> >>> In case of mistakes or missed proposals, let me know. >>> >>> Cheers, >>> Stefan >>> >>> >>> 0. Common syntax >>> Block: >>> ? ? { BlockStatements } >>> >>> BlockStatements: >>> ? ? BlockStatement >>> ? ? BlockStatements BlockStatement >>> >>> BlockStatement: >>> ? ? LocalVariableDeclarationStatement >>> ? ? ClassDeclaration >>> ? ? Statement >>> >>> ParameterList: >>> ? ? Parameter >>> ? ? Parameter, ParameterList >>> >>> Parameter: >>> ? ? Type Identifier >>> >>> 1. Straw-man, latest >>> Proposes two lambda definitions: lambda expressions and statements. >>> Return type is inferred and throws meant to be transparent. >>> >>> LambdaExpression: >>> ? ? # ( ParameterListopt ) ( Expression ) >>> ? ? # ( ParameterListopt ) Block >>> >>> Examples: >>> #() ( 7 ); >>> #(Event e) { handle(e); } >>> #(File f) { return f.getName(); }; >>> #(#R(A)(throws E) l, A a) ( #() ( l.(a) ) ); >>> >>> >>> 2. R?my Forax, 05 Jan 2010 >>> Proposes to use a keyword lambda instead of #. >>> >>> LambdaExpression: >>> ? ? lambda ( ParameterListopt ) ( Expression ) >>> ? ? lambda ( ParameterListopt ) Block >>> >>> Examples: >>> lambda() ( 7 ); >>> lambda(Event e) { handle(e); }; >>> lambda(File f) { return f.getName(); }; >>> lambda(#R(A)(throws E) l, A a) ( lambda() ( l.(a) ) ); >>> >>> 3. Peter Levart, 26 Jan 2010 >>> LambdaExpression: >>> ? ? # ( ParametersListopt ResultParameteropt ) Block >>> >>> ResultParameter: >>> ? ? : Parameter >>> >>> Examples: >>> #(: int i) { i = 7 }; >>> #(Event e) { handle(e); }; >>> #(File f : String s) { s = f.getName(); }; >>> #(#(A: R throws E) l, A a : #(: R throws E) c) { c = #(: R r) { r = >>> l.(a); }; }; >>> >>> 4. Peter Levart, 1 Feb 2010 >>> LambdaExpression: >>> ? ? # ( ParameterListopt -> ReturnTypeopt ) Block >>> >>> Examples: >>> #(->int) { return 7; }; >>> #(Event e -> void) { handle(e); }; >>> #(File f -> String) { return f.getName(); }; >>> #(#(A -> R throws E) l, A a >>> ? -> #(-> R throws E)) { return #(->R) { return l.(a); }; }; >>> >>> 5. Neal Gafter, 9 Feb 2010 >>> LambdaExpression: >>> ? ? ( ParameterListopt ) -> Expression >>> ? ? ( ParameterListopt ) -> Block >>> >>> Examples: >>> () -> 7; >>> (Event e) -> { handle(e); }; >>> (File f) -> { return f.getName(); }; >>> ((A) -> R throws E l, A a) -> () -> l.(a); >>> >>> 6. BGGA >>> LambdaExpression: >>> ? ? { ParameterListopt => BlockStatementsopt Expressionopt } >>> >>> Examples: >>> { => 7 } >>> { Event e => handle(e); }; >>> { File f => f.getName() }; >>> { { A => R throws E } l, A a => { => l.(a) } }; >>> >>> 7. Peter Levart, 2 Mar 2010 >>> LambdaExpression: >>> ? ? ( ParameterListopt -> BlockStatementsopt Expression ) >>> >>> Examples: >>> ( -> 7 ); >>> ( Event e -> handle(e); void }; >>> ( File f -> f.getName() ); >>> ( (A -> R throws E ) l, A a -> ( -> l.(a) ) ); >>> >>> 8. Howard Lovatt, 11 Mar 2010 >>> LambdaExpression: >>> ? ? new #< Signature > ( BlockStatementsopt Expression ) >>> Signature: >>> ? ? ReturnType ( ParameterListopt ) Throwsopt >>> >>> Examples: >>> new #< int() > (7); >>> new #< void(Event e) > (handle(e); null); >>> new #< String(File f) > (f.getName()); >>> #< #< R() throws E >( #< R( A ) throws E > l, A a ) > >>> ? ( new #< R() throws E >()( l.( a ) ); >>> >>> 9. C++ (via Stephen Colebourne), 14 Mar 2010 >>> (translated to lambda-use) >>> >>> LambdaExpression: >>> > From reinier at zwitserloot.com Thu Mar 18 21:43:41 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 19 Mar 2010 05:43:41 +0100 Subject: Something simpler? In-Reply-To: <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> Message-ID: <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> I don't follow the argumentation used here. As far as I understand it, the only stated reason for why symbols that already have meaning shouldn't be used for something entirely different is because it might be confusing to those programmers who know of the existing feature but not of the new feature. Just about every java programmer knows about javadoc. Therefore, either will be equally confusing. Also, you say that you'd be very concerned if () was used for something other than parameter definitions, but it is already! It's not just already used for casts and expression precedence grouping, it is also used as delimiter in multi-argument statements (while, do/until, for, synchronized, if, and catch), and in the Reinhold Strawman, it is used BOTH as delimiter in a function type description, and as a block delimiter with implicit "return " at the beginning and ";" at the end. It's used everywhere. Unless the argument is "parens are already such a grab-bag, anyone seeing them will not be tempted to assume they mean any one particular thing". That seems like a rather silly argument as it leads to packing still more semantic meaning on top of an already semantically overcrowded symbol, making the problem worse. I also strongly disagree that generics added readability complexity. On the contrary; they massively reduced it. In the old days, you saw "List" and you didn't know that much. In the 1.5+ days, you see "List>" and you know a lot more than you used to. Now you can read it right there on the spot. In the past you had to read entire paragraphs, sometimes multiple pages worth of source before you could figure out what that "List" even meant. Either way, though, the semantic meaning contained inside a function type + closure definition pair is equal between the Reinhold Strawman and the Levart Brace syntax, so generics doesn't seem relevant. --Reinier Zwitserloot On Fri, Mar 19, 2010 at 3:16 AM, Knox, Liam wrote: > # - used already in java doc > [] - used already in java code > > Being ambiguous in the Java Syntax seems much more concerning to me in > these proposals > Being only a 'java programmer', I would not be happy with a syntax that > introduces ambiguity in reading the code within a source file > {} as blocks and () for parameter definitions are very bread and butter in > the understanding of all Java programmers > > readability vs. functionality needs to be weighed up, as with Generics, for > all their good, they did add a fair amount of readability complexity > > Two cents worth > > [:int] two = (:2); > > assert two[] == 2; > > Does not look like something simpler, and personally doesn't feel like Java > > -----Original Message----- > From: lambda-dev-bounces at openjdk.java.net [mailto: > lambda-dev-bounces at openjdk.java.net] On Behalf Of Reinier Zwitserloot > Sent: Friday, March 19, 2010 10:49 AM > To: Joshua Bloch > Cc: lambda-dev > Subject: Re: Something simpler? > > But "#", from its javadoc roots, suggests type member, which is just as > completely off base as [] suggesting array access. If we want lean syntax I > think overloading the semantic meaning of a few symbols is inevitable. It > would be good if we picked symbols that read naturally yet don't have too > many commonly used meanings in today's java, and with arrays moving ever > further towards the background, [] is a fair suggestion. > > FWIW, I would prefer it if closure invoke remained .(), because unlike any > of the other usage of [] in the Levart Bracket proposal, that *can* be > mistaken for array deref. > > Then again, there's a coin proposal that was taken quite seriously which > aims to introduce operator overloading to java and make > expressionA[expressionB] mean: Check if expressionA implements > ListAddressable, and if so, compile this expression as if it read > expressionA.get(expressionB). The theory here is presumably that doing an > indexed retrieval on a list-like object is sufficiently similar to an array > access that using brackets is acceptable. But that's not the end of that > particular line of thought - you end up with the conclusion that calling a > method that takes 1 integer and returns something is theoretically > retrofittable as 'list-like' and as there are plenty of concepts that aren't > really implemented as physical list-like constructions that nevertheless > could and probably will end up as such ListAddressable instances (such as > e.g range(10,1000)), we must conclude that in fact any method call is > sufficiently similar to arrays, so that if this ListAccessible proposal is > acceptable, then brackets are acceptable for methods. > > And if method calls are sufficiently similar to array access, then so is > closure invocation. > > There's also the idea of allowing [] or {} to be used for collection > literals. {} in java right now means "block" or "body" and nothing else. It > has nothing to do with maps or even literals. Your same argument would apply > there. Why is this the first time you're complaining about '[', ']', '{' and > '}' being used for things that don't mean what they do in Java6? If anything > this proposal should receive _more_ leniency than the others, because its > already so complicated in other areas, too. > > Just playing advocate of the devil. Personal vote: Go with .() instead, and > the reasoned argument behind it is this: [] is for arrays and not for > anything else. Don't introduce [] access for Lists either*. > > > *) Or, tilt the other way and go whole hog with operator overloading. > Consistency is worth something. > > --Reinier Zwitserloot > > > > On Thu, Mar 18, 2010 at 11:28 PM, Joshua Bloch wrote: > > > Reinier, > > > > On Wed, Mar 17, 2010 at 9:13 PM, Reinier Zwitserloot < > > reinier at zwitserloot.com> wrote: > > > >> I just don't understand how this works. Some syntax doesn't feel > >> right to someone, and the magic words "This isn't java" are spoken. > >> Is there some sort of device to measure this property? I'd love to > >> get my hands on a javometer. > > > > > > I don't have a Javometer, but my assertion isn't arbitrary, and it > > isn't purely aesthetic (though it does have an aesthetic component). > > Looking at the proposed syntax, I can tell you why it doesn't look like > Java: > > > > [:int] two = (:2); > > assert two[] == 2; > > > > > > Java declares return types *before* variables and doesn't use the > > colon to indicate the return type. Other languages (such as Pascal and > > Scala) put the types after the variable name, separated by a colon. So > > this is a specific point where the proposed syntax deviates from > > established Java norms. > > > > Also, brackets strongly suggest arrays to existing Java programmers, > > especially when preceded by an identifier. This is even more true if > > the brackets contain an integer-valued expression: > > > > assert x[i] == 42; > > > > If x[i] could be a lambda invocation as well as an array reference in > > the above statement, we've done real harm to the language. > > > > Josh > > > > > -------------------------------------------------------------------------- > NOTICE: If received in error, please destroy, and notify sender. Sender > does not intend to waive confidentiality or privilege. Use of this email is > prohibited when received in error. We may monitor and store emails to the > extent permitted by applicable law. > From Liam.Knox at morganstanley.com Thu Mar 18 22:20:57 2010 From: Liam.Knox at morganstanley.com (Knox, Liam) Date: Fri, 19 Mar 2010 14:20:57 +0900 Subject: Something simpler? In-Reply-To: <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> Message-ID: <7C638926FF9E05448A777589A4B6AB701556FA7904@TKWEXMBX0043.msad.ms.com> 1. Look at wild cards and Generics and say they are easy to read/understand. They do add complexity 2. Look at this [:int] two = (:2); assert two[] == 2; a. is it easy to understand? b. Does it look like Java ? Put it to a poll if you like. I can't make head nor tail of it. 3. I did not say I was very concerned if () was used, do not invent what I said. I said I was concerned with introducing ambiguity. Of course I know where else () is used, that is not the point. If you are expressing blocks of behavior use { } as it is most familiar, if you are expressing params use (), if you want to express something else, use something else Basically I am coming from a perspective of someone who uses this language everyday for year on end, and understands the need for Closures. Given that I am still using this language and not another one probably says a lot of what a success Java is and paramount to this succes is its simplicity. What I don't want now is some Closure syntax the divereges from the current shape of the language and makes it a lot harder to understand and maintain for me and teams of developers with varying experience. I don't want Java++ >From this debate I am not sure if you are looking at this as too much of an academic exercise in to what possible notation could cover every edge case, rather than being more pragmatic in the way Closures will feel and be used in the main. Based on this debate clearly Gosling was right (or lucky) not to add them from the start. ________________________________ From: reinierz at gmail.com [mailto:reinierz at gmail.com] On Behalf Of Reinier Zwitserloot Sent: Friday, March 19, 2010 1:44 PM To: Knox, Liam (IDEAS) Cc: Joshua Bloch; lambda-dev Subject: Re: Something simpler? I don't follow the argumentation used here. As far as I understand it, the only stated reason for why symbols that already have meaning shouldn't be used for something entirely different is because it might be confusing to those programmers who know of the existing feature but not of the new feature. Just about every java programmer knows about javadoc. Therefore, either will be equally confusing. Also, you say that you'd be very concerned if () was used for something other than parameter definitions, but it is already! It's not just already used for casts and expression precedence grouping, it is also used as delimiter in multi-argument statements (while, do/until, for, synchronized, if, and catch), and in the Reinhold Strawman, it is used BOTH as delimiter in a function type description, and as a block delimiter with implicit "return " at the beginning and ";" at the end. It's used everywhere. Unless the argument is "parens are already such a grab-bag, anyone seeing them will not be tempted to assume they mean any one particular thing". That seems like a rather silly argument as it leads to packing still more semantic meaning on top of an already semantically overcrowded symbol, making the problem worse. I also strongly disagree that generics added readability complexity. On the contrary; they massively reduced it. In the old days, you saw "List" and you didn't know that much. In the 1.5+ days, you see "List>" and you know a lot more than you used to. Now you can read it right there on the spot. In the past you had to read entire paragraphs, sometimes multiple pages worth of source before you could figure out what that "List" even meant. Either way, though, the semantic meaning contained inside a function type + closure definition pair is equal between the Reinhold Strawman and the Levart Brace syntax, so generics doesn't seem relevant. --Reinier Zwitserloot On Fri, Mar 19, 2010 at 3:16 AM, Knox, Liam > wrote: # - used already in java doc [] - used already in java code Being ambiguous in the Java Syntax seems much more concerning to me in these proposals Being only a 'java programmer', I would not be happy with a syntax that introduces ambiguity in reading the code within a source file {} as blocks and () for parameter definitions are very bread and butter in the understanding of all Java programmers readability vs. functionality needs to be weighed up, as with Generics, for all their good, they did add a fair amount of readability complexity Two cents worth [:int] two = (:2); assert two[] == 2; Does not look like something simpler, and personally doesn't feel like Java -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Reinier Zwitserloot Sent: Friday, March 19, 2010 10:49 AM To: Joshua Bloch Cc: lambda-dev Subject: Re: Something simpler? But "#", from its javadoc roots, suggests type member, which is just as completely off base as [] suggesting array access. If we want lean syntax I think overloading the semantic meaning of a few symbols is inevitable. It would be good if we picked symbols that read naturally yet don't have too many commonly used meanings in today's java, and with arrays moving ever further towards the background, [] is a fair suggestion. FWIW, I would prefer it if closure invoke remained .(), because unlike any of the other usage of [] in the Levart Bracket proposal, that *can* be mistaken for array deref. Then again, there's a coin proposal that was taken quite seriously which aims to introduce operator overloading to java and make expressionA[expressionB] mean: Check if expressionA implements ListAddressable, and if so, compile this expression as if it read expressionA.get(expressionB). The theory here is presumably that doing an indexed retrieval on a list-like object is sufficiently similar to an array access that using brackets is acceptable. But that's not the end of that particular line of thought - you end up with the conclusion that calling a method that takes 1 integer and returns something is theoretically retrofittable as 'list-like' and as there are plenty of concepts that aren't really implemented as physical list-like constructions that nevertheless could and probably will end up as such ListAddressable instances (such as e.g range(10,1000)), we must conclude that in fact any method call is sufficiently similar to arrays, so that if this ListAccessible proposal is acceptable, then brackets are acceptable for methods. And if method calls are sufficiently similar to array access, then so is closure invocation. There's also the idea of allowing [] or {} to be used for collection literals. {} in java right now means "block" or "body" and nothing else. It has nothing to do with maps or even literals. Your same argument would apply there. Why is this the first time you're complaining about '[', ']', '{' and '}' being used for things that don't mean what they do in Java6? If anything this proposal should receive _more_ leniency than the others, because its already so complicated in other areas, too. Just playing advocate of the devil. Personal vote: Go with .() instead, and the reasoned argument behind it is this: [] is for arrays and not for anything else. Don't introduce [] access for Lists either*. *) Or, tilt the other way and go whole hog with operator overloading. Consistency is worth something. --Reinier Zwitserloot On Thu, Mar 18, 2010 at 11:28 PM, Joshua Bloch > wrote: > Reinier, > > On Wed, Mar 17, 2010 at 9:13 PM, Reinier Zwitserloot < > reinier at zwitserloot.com> wrote: > >> I just don't understand how this works. Some syntax doesn't feel >> right to someone, and the magic words "This isn't java" are spoken. >> Is there some sort of device to measure this property? I'd love to >> get my hands on a javometer. > > > I don't have a Javometer, but my assertion isn't arbitrary, and it > isn't purely aesthetic (though it does have an aesthetic component). > Looking at the proposed syntax, I can tell you why it doesn't look like Java: > > [:int] two = (:2); > assert two[] == 2; > > > Java declares return types *before* variables and doesn't use the > colon to indicate the return type. Other languages (such as Pascal and > Scala) put the types after the variable name, separated by a colon. So > this is a specific point where the proposed syntax deviates from > established Java norms. > > Also, brackets strongly suggest arrays to existing Java programmers, > especially when preceded by an identifier. This is even more true if > the brackets contain an integer-valued expression: > > assert x[i] == 42; > > If x[i] could be a lambda invocation as well as an array reference in > the above statement, we've done real harm to the language. > > Josh > -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law. -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law. From schulz at the-loom.de Fri Mar 19 04:00:04 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Fri, 19 Mar 2010 12:00:04 +0100 Subject: Summary: Lambda syntax In-Reply-To: <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> Message-ID: <4BA35934.4060005@the-loom.de> Am 19.03.2010 01:04, schrieb Alex Blewitt: > There are inconsistencies in 7, 16 and 17. One is missing a "throws", > one declares that it uses PipedException but then uses commas, and one > has another error I have forgotten (another missing throws?) Fixed 7 and 17 (had "Throws" instead of "Exceptions"). In 16 I don't see any error. As the examples (unfortunately?) only always have at max one exception, there is no need for pipes. > In addition, the example with "new" probably shouldn't be included, > since it's not valid for all lambdas, regardless of the syntax used for > representing the lambdas themselves. The new word is part of the syntax (cf. to Howard's post). Stefan From schulz at the-loom.de Fri Mar 19 04:00:42 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Fri, 19 Mar 2010 12:00:42 +0100 Subject: Summary: Lambda syntax In-Reply-To: <3dd3f56a1003181930i14212e80kba31e4d48ef3b48@mail.gmail.com> References: <3dd3f56a1003181930i14212e80kba31e4d48ef3b48@mail.gmail.com> Message-ID: <4BA3595A.4050308@the-loom.de> I adjusted the syntax and examples. Stefan Am 19.03.2010 03:30, schrieb Howard Lovatt: > Great summary of the various syntaxes. For my proposal, your B8, I think > a description that fits my 'intent' is: > From alex.blewitt at gmail.com Fri Mar 19 05:54:08 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Fri, 19 Mar 2010 12:54:08 +0000 Subject: Summary: Lambda syntax In-Reply-To: <4BA35934.4060005@the-loom.de> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> <4BA35934.4060005@the-loom.de> Message-ID: <7C3114DA-D7E3-4692-BD5A-5C08BD310093@gmail.com> On 19 Mar 2010, at 11:00, Stefan Schulz wrote: > Am 19.03.2010 01:04, schrieb Alex Blewitt: > Fixed 7 and 17 (had "Throws" instead of "Exceptions"). > In 16 I don't see any error. As the examples (unfortunately?) only > always have at max one exception, there is no need for pipes. 16. R?mi Forax, 14 Mar 2010 FunctionType: ResultType ( TypeListopt ) PipedExceptionsopt Examples: int() String(File) throws IOException R() throws E (R(A) throws E, A) > I interpreted that as having two comma separated exceptions, but if that isn't the intent then the mistake is mine. >> In addition, the example with "new" probably shouldn't be included > > The new word is part of the syntax (cf. to Howard's post). The use of "new" isn't a syntax issue; it's a semantic error in the laguage. Whilst trivial examples may hint that a JVM should be able to in-line, in practical cases (returning the lambda from the function) will not be able to make such guarantees, particularly due to identity issues (like the possibility of .wait() and .notify() on a lambda) which have specific meaning on the case of new'd things in Java. Experience in codebases using inner classes as closures (and lambdas too) suggests that excessive new'ing of such items and returning causes significant churn in the new generation space, to the extent that assigning such lambdas to static final variables had to be done to avoid this behaviour. In other words, this approach has already been demonstrated not to work. Alex From reinier at zwitserloot.com Fri Mar 19 06:34:52 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Fri, 19 Mar 2010 14:34:52 +0100 Subject: Something simpler? In-Reply-To: <7C638926FF9E05448A777589A4B6AB701556FA7904@TKWEXMBX0043.msad.ms.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA7904@TKWEXMBX0043.msad.ms.com> Message-ID: <560fb5ed1003190634l862821uc190187cb724403b@mail.gmail.com> On Fri, Mar 19, 2010 at 6:20 AM, Knox, Liam wrote: > 1. Look at wild cards and Generics and say they are easy to > read/understand. They do add complexity > The complexity added by generics is inherent in the code. Since 1.5 it has been made visible. When you see a List you need to know what you can put in it, and what you can expect when you take objects out of it. Making complexities visible makes things easier to understand and less complex to read. The difference between Levart Brackets and Reinhold Strawman is a completely different story. The semantic complexity is the same, it's just a matter of what's easier to look at. > > 2. Look at this > > [:int] two = (:2); > > assert two[] == 2; > > a. is it easy to understand? > Yes, once you've been told you're looking at closures. As I've also said ad nauseam, especially the invocation (assert two[] == 2) would look better to me as assert two.() == 2. You're also asking entirely the wrong question. The right question is: Is it eas*IER* to understand than: #int() two = ()(2); assert two.() == 2; and the answer to me is clearly: Just as difficult, though the one with the brackets is easier to read at-a-glance once you're familiar with the concept. What would possibly cause someone to jump to the conclusion that the empty pair of parens in front of the (2) is a parameter listing? I grant you that {} will most likely suggest 'code block', but parens are used in far too many places to suggest parens list. > b. Does it look like Java ? > No more, and no less, than Reinhold Strawman closures. Which is mostly to say: Less. The following WOULD 'look more like Java' to me, though I'll just call it without the euphemisms: I have a personal preference for: public interface Producer { T produce(); } Producer two = (:2); assert two.produce() == 2; > > 3. I did not say I was very concerned if () was used, do not invent what I > said. I said I was concerned with introducing ambiguity. > Of course I know where else () is used, that is not the point. > You defended the use of () as not introducing ambiguity, and/or being intuitive, and I pointed out that the idea that () is intuitive doesn't work, because its already used everywhere and thus has become mostly meaningless. > If you are expressing blocks of behavior use { } as it is most familiar, if > you are expressing params use (), if you want to express something else, use > something else > The Levart Brackets proposal does use {}. Its alternative colon-based syntax for param usage is specifically as a response to concerns about readability, and to differentiate function types from the closures themselves, something Reinhold Strawman is bad at. > > Basically I am coming from a perspective of someone who uses this language > everyday for year on end > Just like me then. > Given that I am still using this language and not another one probably says > a lot of what a success Java is and paramount to this > succes is its simplicity. > Sure. Please define Simplicity. I'd say being able to easily differentiate between a function type and a closure is part of whatever definition you end up with. So is being able to read intent of code at a glance which is harder when a parade of parentheses is involved. Brains are bad at matching parens. > > I don't want Java++ > Brackets instead of parens means Java turned into Java++? That feels like overstating the case just a tad. > > Based on this debate clearly Gosling was right (or lucky) not to add them > from the start. > Where is this conclusion coming from? If java used [] for closures from the start you wouldn't be making this complaint, and this mailing list wouldn't be bending itself backwards to attempt to come up with some sort of syntax that is readable, somewhat intuitive, and doesn't conflict with existing java syntax. That last one wouldn't have been a concern if it had been in java from day 1. From jkuhnert at gmail.com Fri Mar 19 07:06:50 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Fri, 19 Mar 2010 10:06:50 -0400 Subject: Something simpler? In-Reply-To: <560fb5ed1003190634l862821uc190187cb724403b@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA7904@TKWEXMBX0043.msad.ms.com> <560fb5ed1003190634l862821uc190187cb724403b@mail.gmail.com> Message-ID: <7926817e1003190706r5ad764aem5bc6d756bd755c2c@mail.gmail.com> I agree that the [] looks ugly, don't have the stamina to read these long-winded and kind of annoying emails all the time though. On Fri, Mar 19, 2010 at 9:34 AM, Reinier Zwitserloot wrote: > On Fri, Mar 19, 2010 at 6:20 AM, Knox, Liam wrote: > >> ?1. Look at wild cards and Generics and say they are easy to >> read/understand. They do add complexity >> > > The complexity added by generics is inherent in the code. Since 1.5 it has > been made visible. When you see a List you need to know what you can put in > it, and what you can expect when you take objects out of it. Making > complexities visible makes things easier to understand and less complex to > read. > > The difference between Levart Brackets and Reinhold Strawman is a completely > different story. The semantic complexity is the same, it's just a matter of > what's easier to look at. > > >> >> 2. Look at this >> >> [:int] two = (:2); >> >> assert two[] == 2; >> >> a. is it easy to understand? >> > > Yes, once you've been told you're looking at closures. As I've also said ad > nauseam, especially the invocation (assert two[] == 2) would look better to > me as assert two.() == 2. You're also asking entirely the wrong question. > The right question is: > > Is it eas*IER* to understand than: > > #int() two = ()(2); > > assert two.() == 2; > > and the answer to me is clearly: Just as difficult, though the one with the > brackets is easier to read at-a-glance once you're familiar with the > concept. What would possibly cause someone to jump to the conclusion that > the empty pair of parens in front of the (2) is a parameter listing? I grant > you that {} will most likely suggest 'code block', but parens are used in > far too many places to suggest parens list. > > >> b. Does it look like Java ? >> > > No more, and no less, than Reinhold Strawman closures. Which is mostly to > say: Less. The following WOULD 'look more like Java' to me, though I'll just > call it without the euphemisms: I have a personal preference for: > > public interface Producer { > ? ?T produce(); > } > > Producer two = (:2); > assert two.produce() == 2; > > > >> >> 3. I did not say I was very concerned if ?() was used, do not invent what I >> said. I said I was concerned with introducing ambiguity. >> Of course I know where else () is used, that is not the point. >> > > You defended the use of () as not introducing ambiguity, and/or being > intuitive, and I pointed out that the idea that () is intuitive doesn't > work, because its already used everywhere and thus has become mostly > meaningless. > > >> If you are expressing blocks of behavior use { } as it is most familiar, if >> you are expressing params use (), if you want to express something else, use >> something else >> > > The Levart Brackets proposal does use {}. Its alternative colon-based syntax > for param usage is specifically as a response to concerns about readability, > and to differentiate function types from the closures themselves, something > Reinhold Strawman is bad at. > > >> >> Basically I am coming from a perspective of someone who uses this language >> everyday for year on end >> > > Just like me then. > > >> Given that I am still using this language and not another one probably says >> a lot of what a success Java is and paramount to this >> succes is its simplicity. >> > > Sure. Please define Simplicity. I'd say being able to easily differentiate > between a function type and a closure is part of whatever definition you end > up with. So is being able to read intent of code at a glance which is harder > when a parade of parentheses is involved. Brains are bad at matching parens. > > >> >> I don't want Java++ >> > > Brackets instead of parens means Java turned into Java++? That feels like > overstating the case just a tad. > > >> >> > Based on this debate clearly Gosling was right (or lucky) not to add them >> from the start. >> > > Where is this conclusion coming from? If java used [] for closures from the > start you wouldn't be making this complaint, and this mailing list wouldn't > be bending itself backwards to attempt to come up with some sort of syntax > that is readable, somewhat intuitive, and doesn't conflict with existing > java syntax. That last one wouldn't have been a concern if it had been in > java from day 1. > > From schulz at the-loom.de Fri Mar 19 07:40:15 2010 From: schulz at the-loom.de (Stefan Schulz) Date: Fri, 19 Mar 2010 15:40:15 +0100 Subject: Summary: Lambda syntax In-Reply-To: <7C3114DA-D7E3-4692-BD5A-5C08BD310093@gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> <4BA35934.4060005@the-loom.de> <7C3114DA-D7E3-4692-BD5A-5C08BD310093@gmail.com> Message-ID: <4BA38CCF.7010800@the-loom.de> Am 19.03.2010 13:54, schrieb Alex Blewitt: > R() throws E (R(A) throws E, A) > > I interpreted that as having two comma separated exceptions, but if that > isn't the intent then the mistake is mine. It's the same example like in the other proposals having two parameters, one being a function type the other being A. But I think that many Java developers might be confused by this kind of syntax, especially, if A is an Exception-type as well. > The use of "new" isn't a syntax issue; it's a semantic error in the > laguage. Ok, now I got it. I'll leave it in, as it still is a proposal from this list and one could possibly substitute "new" with some other keyword to make it proper (e.g. using "const" defining its meaning to be "construct" ;)). Stefan From john at milsson.nu Fri Mar 19 12:53:44 2010 From: john at milsson.nu (John Nilsson) Date: Fri, 19 Mar 2010 20:53:44 +0100 Subject: Summary: Lambda syntax In-Reply-To: <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> References: <4b4f45e01003141056u682e4541t4fac8c792a4c51f7@mail.gmail.com> <4BA0A3A3.1000108@the-loom.de> <4BA2B2B8.5060303@the-loom.de> <8CF05D72-B448-4254-A4FA-F9E1F9D6B995@gmail.com> Message-ID: For completeness I've tried to formalize my earlier suggestion as follows. The intent is that the number identifies position in argument list. Argument types are inferred. A lambda expression with n arguments can be coerced into a lambda expression taking n+m arguments, where the other m arguments are ignored, and any expression can be coerced into a lambda expression. LambdaExpression: # DecimalNumeral # ( Expression ) Examples: 7 #(handle(#0)) #0.getName() #0.(#1) BR, John From howard.lovatt at gmail.com Fri Mar 19 13:39:07 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sat, 20 Mar 2010 07:39:07 +1100 Subject: Summary: Lambda syntax Message-ID: <61D1F7B1-D16A-4E45-8681-2354C40E0014@gmail.com> Stefan, I made a mistake in the examples I sent to you. Can you correct the curry examples to: new #< #< R() throws E >( #< R( A ) throws E > l, A a ) > ( new #< R() throws E >( l.( a ) ); new # ( new #<>()( l.( a ) ); Sorry, -- Howard Lovatt +61 419 971 263 (sent from my PDA) From Liam.Knox at morganstanley.com Fri Mar 19 14:05:39 2010 From: Liam.Knox at morganstanley.com (Knox, Liam) Date: Sat, 20 Mar 2010 06:05:39 +0900 Subject: Something simpler? In-Reply-To: <560fb5ed1003190634l862821uc190187cb724403b@mail.gmail.com> References: <201003170113.40897.peter.levart@gmail.com> <17b2302a1003170110r68645e50u21ecee134332f892@mail.gmail.com> <560fb5ed1003172113t4f8e6a2fn560df00b3cf258a5@mail.gmail.com> <17b2302a1003181528m4fb09d6bj9245254a68429eb@mail.gmail.com> <560fb5ed1003181848g5e1e0314sda81a729d7cf6cb9@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA78A3@TKWEXMBX0043.msad.ms.com> <560fb5ed1003182143o55b53be3p72ce3906fd60c299@mail.gmail.com> <7C638926FF9E05448A777589A4B6AB701556FA7904@TKWEXMBX0043.msad.ms.com> <560fb5ed1003190634l862821uc190187cb724403b@mail.gmail.com> Message-ID: <7C638926FF9E05448A777589A4B6AB701556FA79BD@TKWEXMBX0043.msad.ms.com> I dont want to drag this on, but basically if this [:int] two = (:2); assert two[] == 2; Is the 'simplest' proposal of syntax I would fundamentally disagree and yes even your other demonstrated syntax, though not great, is more readable. ________________________________ From: reinierz at gmail.com [mailto:reinierz at gmail.com] On Behalf Of Reinier Zwitserloot Sent: Friday, March 19, 2010 10:35 PM To: Knox, Liam (IDEAS) Cc: Joshua Bloch; lambda-dev Subject: Re: Something simpler? On Fri, Mar 19, 2010 at 6:20 AM, Knox, Liam > wrote: 1. Look at wild cards and Generics and say they are easy to read/understand. They do add complexity The complexity added by generics is inherent in the code. Since 1.5 it has been made visible. When you see a List you need to know what you can put in it, and what you can expect when you take objects out of it. Making complexities visible makes things easier to understand and less complex to read. The difference between Levart Brackets and Reinhold Strawman is a completely different story. The semantic complexity is the same, it's just a matter of what's easier to look at. 2. Look at this [:int] two = (:2); assert two[] == 2; a. is it easy to understand? Yes, once you've been told you're looking at closures. As I've also said ad nauseam, especially the invocation (assert two[] == 2) would look better to me as assert two.() == 2. You're also asking entirely the wrong question. The right question is: Is it eas*IER* to understand than: #int() two = ()(2); assert two.() == 2; and the answer to me is clearly: Just as difficult, though the one with the brackets is easier to read at-a-glance once you're familiar with the concept. What would possibly cause someone to jump to the conclusion that the empty pair of parens in front of the (2) is a parameter listing? I grant you that {} will most likely suggest 'code block', but parens are used in far too many places to suggest parens list. b. Does it look like Java ? No more, and no less, than Reinhold Strawman closures. Which is mostly to say: Less. The following WOULD 'look more like Java' to me, though I'll just call it without the euphemisms: I have a personal preference for: public interface Producer { T produce(); } Producer two = (:2); assert two.produce() == 2; 3. I did not say I was very concerned if () was used, do not invent what I said. I said I was concerned with introducing ambiguity. Of course I know where else () is used, that is not the point. You defended the use of () as not introducing ambiguity, and/or being intuitive, and I pointed out that the idea that () is intuitive doesn't work, because its already used everywhere and thus has become mostly meaningless. If you are expressing blocks of behavior use { } as it is most familiar, if you are expressing params use (), if you want to express something else, use something else The Levart Brackets proposal does use {}. Its alternative colon-based syntax for param usage is specifically as a response to concerns about readability, and to differentiate function types from the closures themselves, something Reinhold Strawman is bad at. Basically I am coming from a perspective of someone who uses this language everyday for year on end Just like me then. Given that I am still using this language and not another one probably says a lot of what a success Java is and paramount to this succes is its simplicity. Sure. Please define Simplicity. I'd say being able to easily differentiate between a function type and a closure is part of whatever definition you end up with. So is being able to read intent of code at a glance which is harder when a parade of parentheses is involved. Brains are bad at matching parens. I don't want Java++ Brackets instead of parens means Java turned into Java++? That feels like overstating the case just a tad. Based on this debate clearly Gosling was right (or lucky) not to add them from the start. Where is this conclusion coming from? If java used [] for closures from the start you wouldn't be making this complaint, and this mailing list wouldn't be bending itself backwards to attempt to come up with some sort of syntax that is readable, somewhat intuitive, and doesn't conflict with existing java syntax. That last one wouldn't have been a concern if it had been in java from day 1. -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law. From int19h at gmail.com Fri Mar 19 14:12:48 2010 From: int19h at gmail.com (Pavel Minaev) Date: Fri, 19 Mar 2010 14:12:48 -0700 Subject: How about a combo? Message-ID: On one hand, I really like Howard's angle-brackets proposal in the variety where a magic type is used rather than #, or other Perlesque "magic symbol". For example: java.lang.Function f; Naturally you'd omit java.lang normally, as with other types from that package. >From syntax perspective, this would mean an alternative production of what may be inside the angle brackets for a type name. The syntax for that production is the same as the existing MethodHeader production without MethodModifiers and TypeParameters, and with name of method itself and all parameters omitted. Such a production would only be allowed as a type argument for the "magic" class java.lang.Function, which does not have a single normal class declaration (much like arrays do not) - this check would, of course, have to happen after parsing stage. Here are a few more declarations showcasing both simple, and variously convoluted cases: java.lang.Function f0; Function f1; Function f2; Function(Function, int) throws E1, E3> f2; The obvious benefit of this syntax is that it nests relatively cleanly, at least to someone familiar with the existing syntax for generics. I would also argue that playing on the similarity to generics may be a good thing here, if we treat them as an idea of "parametrizing a family of types G with some parameter T" - it's just that, so far, T has always been a list of types, while this extends it further. The basic concept, though, remains the same - "Function" is a family in the same way e.g. "List" is, and it can be parametrized by specifying parameters and return types. At the same time, the syntax within the angle brackets has direct and obvious correspondence to existing method declaration syntax. The advantage over a "magic symbol" is that it better preserves the existing "Java feel" of type references, by which I mean that, so far, all Java types always begin with either one of the few primitive type keywords, or a type name (which, by established convention, is also always capitalized). A "magic symbol" breaks this, and it is precisely this which, in my opinion, creates this feeling of "unnaturalness" about many syntaxes proposed so far that use various non-alphanumeric symbols at the beginning of function type. Note: all syntax above is actually in Howard's proposal (with his own alternations), I didn't add anything new there. The only difference is that he used Lambda as a magic class name. I think that Function is more descriptive in a sense that it would make all implications more obvious to someone not familiar with this syntax (but familiar with Java syntax otherwise), but this is a minor point in any case. Now, lambdas themselves. I like one of Neal's proposals for that, the one which disposes away with any special symbol to mark the start of the expression (and consequently looks a lot like C#): f0 = int() -> 42; f0 = int() { return 42; } f1 = int(int x) -> x * x; f1 = int(int x) { return x * x; }; f2 = void(int x, int y) throws Exception { if (x < y) throw new Exception(); } f2 = void(int x, int y) throws Exception -> foo(); f3 = Function(Function f, int x) throws E1, E3 { return void(int y, int z) throws E1, E2 { f(x * y, x * z); } } The only thing I'd prefer over his grammar is to avoid the need for -> for statement lambdas (which is shown in the examples above). They are unambiguously identified by "{" following ")", anyway. With that amendment, the syntax for statement lambdas directly matches existing syntax for method declarations, except that method name is omitted. The reason to have -> there for expression lambdas is to be able to disambiguate, in a context-free manner, lambdas with generic return types and/or arguments from expressions. E.g.: A (C e) -> ... // expression lambda A (C e) { ... // statement lambda A (C e) ... // a bunch of < and > operator calls So far as I can see, instead of "->", expression could be parenthesized - this is also unambiguous. However, I believe that something like "int(int x)(x * x)" is less readable than "int(int x) -> x * x". Of course, this is subjective. Another, more lengthy option, is to use "return" instead of "->", e.g.: f1 = int(int x) return x * x; It is even more obvious to someone familiar with existing Java syntax, and the extra 4 chars aren't that big of an issue - Java lambdas are going to be pretty verbose anyway in the lack of parameter type inference. And it avoids any possible confusion with the widespread use of -> as member access operator in other syntactically similar languages (C, C++, C#, PHP...). With respect to need to perform unbounded lookahead here to determine if something is a lambda or not, this is, so far as I know, already a problem with generic types & casts, and can be solved in exact same way - backtracking in a context-free parser, or contextual parsing. On type inference. I think that inference for exception specifications on lambdas would be helpful, and would not otherwise negatively affect anything else. Whether this means that "throws" clause in lambda definitions can be dropped altogether, or whether having it to be able to express one's intent explicitly is still a good idea, is an open question. For return type inference, I don't know if it makes much sense if parameter types are not inferred, anyway. Regardless, if desired, the syntax is fairly straightforward: f0 = () -> 42; I foresee one common objection to the overall combination presented above, and that is perceived syntactic inconsistency between function types (which require Function<>), and lambda definitions (which do not). I think that this issue is not as significant as it seems, since 1) the syntaxes are still largely consistent aside from that, and 2) consistency with existing Java concepts for both syntaxes (i.e. with type syntax for function types, and with method declaration syntax for lambda definitions) is, in fact, more important. From Liam.Knox at morganstanley.com Fri Mar 19 16:55:01 2010 From: Liam.Knox at morganstanley.com (Knox, Liam) Date: Sat, 20 Mar 2010 08:55:01 +0900 Subject: How about a combo? In-Reply-To: References: Message-ID: <7C638926FF9E05448A777589A4B6AB701556FA79BF@TKWEXMBX0043.msad.ms.com> f1 = int(int x) { return x * x; }; That feels more like Java tome -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Pavel Minaev Sent: Saturday, March 20, 2010 6:13 AM To: lambda-dev at openjdk.java.net Subject: How about a combo? On one hand, I really like Howard's angle-brackets proposal in the variety where a magic type is used rather than #, or other Perlesque "magic symbol". For example: java.lang.Function f; Naturally you'd omit java.lang normally, as with other types from that package. >From syntax perspective, this would mean an alternative production of what may be inside the angle brackets for a type name. The syntax for that production is the same as the existing MethodHeader production without MethodModifiers and TypeParameters, and with name of method itself and all parameters omitted. Such a production would only be allowed as a type argument for the "magic" class java.lang.Function, which does not have a single normal class declaration (much like arrays do not) - this check would, of course, have to happen after parsing stage. Here are a few more declarations showcasing both simple, and variously convoluted cases: java.lang.Function f0; Function f1; Function f2; Function(Function, int) throws E1, E3> f2; The obvious benefit of this syntax is that it nests relatively cleanly, at least to someone familiar with the existing syntax for generics. I would also argue that playing on the similarity to generics may be a good thing here, if we treat them as an idea of "parametrizing a family of types G with some parameter T" - it's just that, so far, T has always been a list of types, while this extends it further. The basic concept, though, remains the same - "Function" is a family in the same way e.g. "List" is, and it can be parametrized by specifying parameters and return types. At the same time, the syntax within the angle brackets has direct and obvious correspondence to existing method declaration syntax. The advantage over a "magic symbol" is that it better preserves the existing "Java feel" of type references, by which I mean that, so far, all Java types always begin with either one of the few primitive type keywords, or a type name (which, by established convention, is also always capitalized). A "magic symbol" breaks this, and it is precisely this which, in my opinion, creates this feeling of "unnaturalness" about many syntaxes proposed so far that use various non-alphanumeric symbols at the beginning of function type. Note: all syntax above is actually in Howard's proposal (with his own alternations), I didn't add anything new there. The only difference is that he used Lambda as a magic class name. I think that Function is more descriptive in a sense that it would make all implications more obvious to someone not familiar with this syntax (but familiar with Java syntax otherwise), but this is a minor point in any case. Now, lambdas themselves. I like one of Neal's proposals for that, the one which disposes away with any special symbol to mark the start of the expression (and consequently looks a lot like C#): f0 = int() -> 42; f0 = int() { return 42; } f1 = int(int x) -> x * x; f1 = int(int x) { return x * x; }; f2 = void(int x, int y) throws Exception { if (x < y) throw new Exception(); } f2 = void(int x, int y) throws Exception -> foo(); f3 = Function(Function f, int x) throws E1, E3 { return void(int y, int z) throws E1, E2 { f(x * y, x * z); } } The only thing I'd prefer over his grammar is to avoid the need for -> for statement lambdas (which is shown in the examples above). They are unambiguously identified by "{" following ")", anyway. With that amendment, the syntax for statement lambdas directly matches existing syntax for method declarations, except that method name is omitted. The reason to have -> there for expression lambdas is to be able to disambiguate, in a context-free manner, lambdas with generic return types and/or arguments from expressions. E.g.: A (C e) -> ... // expression lambda A (C e) { ... // statement lambda A (C e) ... // a bunch of < and > operator calls So far as I can see, instead of "->", expression could be parenthesized - this is also unambiguous. However, I believe that something like "int(int x)(x * x)" is less readable than "int(int x) -> x * x". Of course, this is subjective. Another, more lengthy option, is to use "return" instead of "->", e.g.: f1 = int(int x) return x * x; It is even more obvious to someone familiar with existing Java syntax, and the extra 4 chars aren't that big of an issue - Java lambdas are going to be pretty verbose anyway in the lack of parameter type inference. And it avoids any possible confusion with the widespread use of -> as member access operator in other syntactically similar languages (C, C++, C#, PHP...). With respect to need to perform unbounded lookahead here to determine if something is a lambda or not, this is, so far as I know, already a problem with generic types & casts, and can be solved in exact same way - backtracking in a context-free parser, or contextual parsing. On type inference. I think that inference for exception specifications on lambdas would be helpful, and would not otherwise negatively affect anything else. Whether this means that "throws" clause in lambda definitions can be dropped altogether, or whether having it to be able to express one's intent explicitly is still a good idea, is an open question. For return type inference, I don't know if it makes much sense if parameter types are not inferred, anyway. Regardless, if desired, the syntax is fairly straightforward: f0 = () -> 42; I foresee one common objection to the overall combination presented above, and that is perceived syntactic inconsistency between function types (which require Function<>), and lambda definitions (which do not). I think that this issue is not as significant as it seems, since 1) the syntaxes are still largely consistent aside from that, and 2) consistency with existing Java concepts for both syntaxes (i.e. with type syntax for function types, and with method declaration syntax for lambda definitions) is, in fact, more important. -------------------------------------------------------------------------- NOTICE: If received in error, please destroy, and notify sender. Sender does not intend to waive confidentiality or privilege. Use of this email is prohibited when received in error. We may monitor and store emails to the extent permitted by applicable law. From int19h at gmail.com Fri Mar 19 17:25:44 2010 From: int19h at gmail.com (Pavel Minaev) Date: Fri, 19 Mar 2010 17:25:44 -0700 Subject: How about a combo? In-Reply-To: References: Message-ID: On Fri, Mar 19, 2010 at 2:12 PM, Pavel Minaev wrote: > ? ?Function f2; > ? ?f2 = void(int x, int y) throws Exception -> foo(); One other advantage to angle brackets approach that I had forgotten - it combines readily with type inference proposal for generics. E.g. the above becomes: Function<> f2 = void(int x, int y) throws Exception -> foo(); I'm actually curious as to how this would be handled in other syntax proposals. From neal at gafter.com Fri Mar 19 17:40:02 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 19 Mar 2010 17:40:02 -0700 Subject: How about a combo? In-Reply-To: References: Message-ID: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> You've got it backwards. The "diamond operator" goes on the "new" expression, not the left-hand-side. And the "throws" goes on a function type, not a lambda expression. Other than that, I can't make heads nor tails of this proposal. On Fri, Mar 19, 2010 at 5:25 PM, Pavel Minaev wrote: > On Fri, Mar 19, 2010 at 2:12 PM, Pavel Minaev wrote: > > Function f2; > > f2 = void(int x, int y) throws Exception -> foo(); > > One other advantage to angle brackets approach that I had forgotten - > it combines readily with type inference proposal for generics. E.g. > the above becomes: > > Function<> f2 = void(int x, int y) throws Exception -> foo(); > > I'm actually curious as to how this would be handled in other syntax > proposals. > > From int19h at gmail.com Fri Mar 19 17:53:04 2010 From: int19h at gmail.com (Pavel Minaev) Date: Fri, 19 Mar 2010 17:53:04 -0700 Subject: How about a combo? In-Reply-To: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> References: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> Message-ID: On Fri, Mar 19, 2010 at 5:40 PM, Neal Gafter wrote: > You've got it backwards.? The "diamond operator" goes on the "new" > expression, not the left-hand-side. My mistake, sorry. > And the "throws" goes on a function type, not a lambda expression. That was intentional. The idea is that lambda expression fully spells out its own type, including exception specification. Whether this is a good idea, or it should be optional (but still allowed, and checked for correctness if present), or it is better to infer it in all scenarios and disallow explicit exception specification altogether, is a valid but separate question. > Other than that, I can't make heads nor tails of this proposal. Do you refer to the type inference bit, or to the proposal in general? If the latter, can you be more specific as to what seems troublesome? From neal at gafter.com Fri Mar 19 19:49:00 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 19 Mar 2010 19:49:00 -0700 Subject: How about a combo? In-Reply-To: References: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> Message-ID: <15e8b9d21003191949n61b9929bx76fcc5bb31192a7f@mail.gmail.com> On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev wrote: > > Other than that, I can't make heads nor tails of this proposal. > > Do you refer to the type inference bit, or to the proposal in general? > > If the latter, can you be more specific as to what seems troublesome? > All of it. I can't be more specific because I'm having trouble figuring out how the parts of the proposal are supposed to fit together. From int19h at gmail.com Fri Mar 19 21:26:17 2010 From: int19h at gmail.com (Pavel Minaev) Date: Fri, 19 Mar 2010 21:26:17 -0700 Subject: How about a combo? In-Reply-To: <15e8b9d21003191949n61b9929bx76fcc5bb31192a7f@mail.gmail.com> References: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> <15e8b9d21003191949n61b9929bx76fcc5bb31192a7f@mail.gmail.com> Message-ID: On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter wrote: > On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev wrote: >> >> > Other than that, I can't make heads nor tails of this proposal. >> >> Do you refer to the type inference bit, or to the proposal in general? >> >> If the latter, can you be more specific as to what seems troublesome? > > All of it.? I can't be more specific because I'm having trouble figuring out > how the parts of the proposal are supposed to fit together. I must admit that I am completely stumped. In terms of syntax, I thought that I had explained it unambiguously, especially given the examples, which don't leave much to speculation. If a more formal grammar is still desired, I can certainly come up with it, but it doesn't look like it is what is causing issues with understanding here. Correct me if I'm wrong. With respect to how "parts fit together" - I don't understand the problem at all. On one hand, there is a function type definition syntax and semantics taken from Howard's angle brackets proposal - calatogued (at http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm) as #13 - and modified by me by replacing # with a reference to a pseudo-class java.lang.Function. Then there is a lambda definition syntax and semantics taken from your arrow proposal - catalogued as #5 - and modified by me by dropping -> when body of lambda is expression rather than block, and by prefixing the parenthesized parameter list with an explicit return type. I do believe that those two proposals thus modified and combined make most sense - most "Java-like" in appearance, if you want - in their respective categories. And, so far as I can see, the categories themselves are fully orthogonal, in a sense that one can easily "pick & match" separately. In what way do you expect to see them fit together? Further references: Howard's proposal (which already replaces # with a pseudo-class) - I only referenced the function type part of that, not the lambda definition part: http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html Your proposal - I only referenced the lambda definition part of that, not the function type part: http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html Does this help? From scolebourne at joda.org Sat Mar 20 05:05:53 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Sat, 20 Mar 2010 12:05:53 +0000 Subject: Options for accessing local variables Message-ID: <4b4f45e01003200505o2ce0be51h874ea04ef812f42@mail.gmail.com> This is a list of possible different ways to link local variables to lambdas. (I spoke to Alex at QCon London about the list). In each case, an example is given, but the syntax isn't that important - its the semantics we are picking. (I've used annotations instead of keywords as it gets the point across more easily: 1) Full access to local variables by reference: int total = 0; Utils.each(list, #(String str) { total += str.length() }); // total is sum of string lengths if each() is not threaded 2) Access to local variables if they are marked by a key word or annotation: @Shared int total = 0; Utils.each(list, #(String str) { total += str.length() }); 3) No access to local variables (example not possible in style it is written - use an AIC?) 4) Only final local variables can be accessed (as with AIC) final int[] total = new int[1]; Utils.each(list, #(String str) { total[0] += str.length() }); 5) Local variables are accessible but copied on construction: int total = 0; Utils.each(list, #(String str) { total += str.length() }); // total still zero here - need different approach for the example 6) Import local variables by reference: int total = 0; Utils.each(list, #(String str : @Share total) { total += str.length() }); 6a) non-imported local variables cannot be seen 6a) non-imported local variables are copied on construction as per #5 7) Import local variables by copy on construction: int total = 0; Utils.each(list, #(String str : @Copy total) { total += str.length() }); // total still zero here - need different approach for the example 7a) non-imported local variables cannot be seen 7a) non-imported local variables are accessed by reference as per #1 8) Mark the lambda as local, allowing full access to local variables: int total = 0; Utils.each(list, @AccessLocal #(String str) { total += str.length() }); 8a) if annotation not present local variables cannot be seen 8a) if annotation not present local variables are copied on construction as per #5 9) Mark the lambda as multi-thread, copying locals on construction: int total = 0; Utils.each(list, @CopyLocals #(String str) { total += str.length() }); 9a) if annotation not present local variables cannot be seen 9a) if annotation not present local variables are accessed by reference as per #1 10) Mark the destination method as local with keyword or annotation: int total = 0; Utils.each(list, #(String str) { total += str.length() }); method declared as: public void each(Collection coll, @Local Block1Arg block) which accesses locals by reference. 11) Mark the destination method as multi-thread with keyword or annotation: int total = 0; Utils.each(list, #(String str) { total += str.length() }); // total still zero here - need different approach for the example (not a closure) method declared as: public void each(Collection coll, @MultiThread Block1Arg block) which accesses locals by copy on construction. NOTE: with #8 and #9, you can't tell from the call-site which type it is. I'm sure that there are other possibilities. And I've not directly addressed the question of "this" (which can be inferred to some degree by picking one of the choices above). I'd also note that "copying on construction" might be a simple copy of the reference, or a full clone. So, in summary - variables can be accessed by reference, or copied on construction. They can be annotated in a variety of different ways to provide choice or to restrict between these two basic choices. Hope this helps someone. I'm offlist for about 3 weeks now. Stephen From neal at gafter.com Sat Mar 20 09:11:33 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 20 Mar 2010 09:11:33 -0700 Subject: Options for accessing local variables In-Reply-To: <4b4f45e01003200505o2ce0be51h874ea04ef812f42@mail.gmail.com> References: <4b4f45e01003200505o2ce0be51h874ea04ef812f42@mail.gmail.com> Message-ID: <15e8b9d21003200911tc224je5b1fa76d0e4513e@mail.gmail.com> You failed to list the choices made in CfJ, the draft specification, and the strawman: CfJ) Full access to local variables, but a warning if a variable is accessed when not annotated and not effectively final. Draft) Access to local variables only if effectively final. Strawman) Full access to local variables if effectively final or a keyword appears on the variable declaration. Cheers, Neal On Sat, Mar 20, 2010 at 5:05 AM, Stephen Colebourne wrote: > This is a list of possible different ways to link local variables to > lambdas. (I spoke to Alex at QCon London about the list). > > In each case, an example is given, but the syntax isn't that important > - its the semantics we are picking. (I've used annotations instead of > keywords as it gets the point across more easily: > > 1) Full access to local variables by reference: > int total = 0; > Utils.each(list, #(String str) { total += str.length() }); > // total is sum of string lengths if each() is not threaded > > 2) Access to local variables if they are marked by a key word or > annotation: > @Shared int total = 0; > Utils.each(list, #(String str) { total += str.length() }); > > 3) No access to local variables > (example not possible in style it is written - use an AIC?) > > 4) Only final local variables can be accessed (as with AIC) > final int[] total = new int[1]; > Utils.each(list, #(String str) { total[0] += str.length() }); > > 5) Local variables are accessible but copied on construction: > int total = 0; > Utils.each(list, #(String str) { total += str.length() }); > // total still zero here - need different approach for the example > > 6) Import local variables by reference: > int total = 0; > Utils.each(list, #(String str : @Share total) { total += str.length() }); > 6a) non-imported local variables cannot be seen > 6a) non-imported local variables are copied on construction as per #5 > > 7) Import local variables by copy on construction: > int total = 0; > Utils.each(list, #(String str : @Copy total) { total += str.length() }); > // total still zero here - need different approach for the example > 7a) non-imported local variables cannot be seen > 7a) non-imported local variables are accessed by reference as per #1 > > 8) Mark the lambda as local, allowing full access to local variables: > int total = 0; > Utils.each(list, @AccessLocal #(String str) { total += str.length() }); > 8a) if annotation not present local variables cannot be seen > 8a) if annotation not present local variables are copied on > construction as per #5 > > 9) Mark the lambda as multi-thread, copying locals on construction: > int total = 0; > Utils.each(list, @CopyLocals #(String str) { total += str.length() }); > 9a) if annotation not present local variables cannot be seen > 9a) if annotation not present local variables are accessed by > reference as per #1 > > 10) Mark the destination method as local with keyword or annotation: > int total = 0; > Utils.each(list, #(String str) { total += str.length() }); > method declared as: > public void each(Collection coll, @Local Block1Arg block) > which accesses locals by reference. > > 11) Mark the destination method as multi-thread with keyword or annotation: > int total = 0; > Utils.each(list, #(String str) { total += str.length() }); > // total still zero here - need different approach for the example > (not a closure) > method declared as: > public void each(Collection coll, @MultiThread Block1Arg block) > which accesses locals by copy on construction. > > NOTE: with #8 and #9, you can't tell from the call-site which type it is. > > > I'm sure that there are other possibilities. And I've not directly > addressed the question of "this" (which can be inferred to some degree > by picking one of the choices above). > > I'd also note that "copying on construction" might be a simple copy of > the reference, or a full clone. > > So, in summary - variables can be accessed by reference, or copied on > construction. They can be annotated in a variety of different ways to > provide choice or to restrict between these two basic choices. > > Hope this helps someone. I'm offlist for about 3 weeks now. > Stephen > > From neal at gafter.com Sat Mar 20 09:28:21 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 20 Mar 2010 09:28:21 -0700 Subject: How about a combo? In-Reply-To: References: <15e8b9d21003191740s4c0b93e4qb3ebb23d39c5519@mail.gmail.com> <15e8b9d21003191949n61b9929bx76fcc5bb31192a7f@mail.gmail.com> Message-ID: <15e8b9d21003200928v7d2cffdbx1481b2496f3a48ce@mail.gmail.com> Howard's syntax combines the generics syntax (outside the angle brackets) with a function type syntax (inside the angle brackets), thereby making the syntax for a function type about twice as complicated as it needs to be. He invents the concept of varargs generics just for this purpose, when in fact there is nothing varargs about disjunctive exception types. To me, his proposal looks like a mess of muddy thinking. I didn't bother commenting earlier because I didn't expect many people to take it seriously. As for the part where you "borrow" my syntax, it isn't my proposed syntax at all. You've added an explicit result type and thrown exceptions, even though every expression already has a type and set of thrown exceptions, and you've added special and too-different forms for statement lambdas. Not quite as muddy as the function type syntax, but it doesn't really appear to have an internal uniform consistency. You've reintroduced an analogy with method declarations that my syntax tries hard to avoid. Cheers, Neal On Fri, Mar 19, 2010 at 9:26 PM, Pavel Minaev wrote: > On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter wrote: > > On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev wrote: > >> > >> > Other than that, I can't make heads nor tails of this proposal. > >> > >> Do you refer to the type inference bit, or to the proposal in general? > >> > >> If the latter, can you be more specific as to what seems troublesome? > > > > All of it. I can't be more specific because I'm having trouble figuring > out > > how the parts of the proposal are supposed to fit together. > > I must admit that I am completely stumped. In terms of syntax, I > thought that I had explained it unambiguously, especially given the > examples, which don't leave much to speculation. If a more formal > grammar is still desired, I can certainly come up with it, but it > doesn't look like it is what is causing issues with understanding > here. Correct me if I'm wrong. > > With respect to how "parts fit together" - I don't understand the > problem at all. > > On one hand, there is a function type definition syntax and semantics > taken from Howard's angle brackets proposal - calatogued (at > http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm) as #13 - and > modified by me by replacing # with a reference to a pseudo-class > java.lang.Function. > > Then there is a lambda definition syntax and semantics taken from your > arrow proposal - catalogued as #5 - and modified by me by dropping -> > when body of lambda is expression rather than block, and by prefixing > the parenthesized parameter list with an explicit return type. > > I do believe that those two proposals thus modified and combined make > most sense - most "Java-like" in appearance, if you want - in their > respective categories. And, so far as I can see, the categories > themselves are fully orthogonal, in a sense that one can easily "pick > & match" separately. In what way do you expect to see them fit > together? > > Further references: > > Howard's proposal (which already replaces # with a pseudo-class) - I > only referenced the function type part of that, not the lambda > definition part: > http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html > > Your proposal - I only referenced the lambda definition part of that, > not the function type part: > http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html > > > Does this help? > From abies at adres.pl Sun Mar 21 00:03:28 2010 From: abies at adres.pl (Artur Biesiadowski) Date: Sun, 21 Mar 2010 08:03:28 +0100 Subject: Options for accessing local variables In-Reply-To: <15e8b9d21003200911tc224je5b1fa76d0e4513e@mail.gmail.com> References: <4b4f45e01003200505o2ce0be51h874ea04ef812f42@mail.gmail.com> <15e8b9d21003200911tc224je5b1fa76d0e4513e@mail.gmail.com> Message-ID: <4BA5C4C0.5030709@adres.pl> Hello One more missing - Variables are copied on construction AND final inside lambda. They can be modified afterwards in calling scope. int[] total = new int[1]; Utils.each(list, #(String str) { total[0] += str.length() }); I think it would be nice to extend the examples with modification of total in calling scope - it is not always clear if variables has to be effectively final or not. Regards, Artur Biesiadowski Neal Gafter wrote: > You failed to list the choices made in CfJ, the draft specification, and the > strawman: > > CfJ) Full access to local variables, but a warning if a variable is accessed > when not annotated and not effectively final. > Draft) Access to local variables only if effectively final. > Strawman) Full access to local variables if effectively final or a keyword > appears on the variable declaration. > > Cheers, > Neal > > On Sat, Mar 20, 2010 at 5:05 AM, Stephen Colebourne wrote: > [...] From howard.lovatt at gmail.com Sun Mar 21 19:24:26 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 22 Mar 2010 13:24:26 +1100 Subject: How about a combo? Message-ID: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> Hi Pavel, I don't have a strong preference between my syntax: #< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > Your syntax: Function< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > Or Gernot Neppert (copied) syntax: lambda< *ReturnType,* *ArgumentTypes,* throws *Exceptions* > They are all consistent with current Java (to a much greater degree than other suggestions), they nest, and you can have arrays of them. Gernot's syntax is the same as that proposed by JSR 292 for method handles, except that he uses 'lambda' and they use 'MehodHandle'. (At least I think it is, JSR 292 is in a state of flux. I have copied John Rose so hopefully he will be able to enlighten me.) The choice between them would really be a matter of style. I chose to use # for two reasons: 1. It was used in the strawman 2. It reminds people that this is not a normal class and that they can't write one of these themselves The choice of using round brackets instead of commas was to be consistent with normal method declarations and was the syntax used in the strawman. With regard to Neal's comments (copied); I am like you, at a loss to see why he cannot understand the proposals. All the proposals, not just those that use <>, are after all relatively minor syntax variations on each other. Stefan Schulz (copied) was able to write a grammar for all the proposals, so clearly he understood them! I didn't find Neal's response to you very enlightening, he said "He [Howard - Me] invents the concept of varargs generics just for this purpose" and "To me, his [Howard - Me] proposal looks like a mess of muddy thinking". With regard to "invents the concept of varargs generics", all the proposals have to deal with a variable number of arguments and exceptions (that's what methods have) and so does MethodHandle (which as noted uses <> also). With regard to "muddy thinking", why is putting <> round some syntax already proposed (strawman) to fix up the problems of consistency, nesting, and arrays muddled? So I don't get why Neal thinks his comments advance the debate about syntax in general or advance the cause of his preferred syntax, surely lambda dev is the ideal place for people to discuss syntax suggestions? And it is not the place "to take your bat home" (good Cricketing term that means "to get upset") if someone disagrees with your preferred option. -- Howard. *On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > wrote:* *On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter > wrote:* >* On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > wrote:*>>**>>* > Other than that, I can't make heads nor tails of this proposal.*>>**>>* Do you refer to the type inference bit, or to the proposal in general?*>>**>>* If the latter, can you be more specific as to what seems troublesome?*>**>* All of it. I can't be more specific because I'm having trouble figuring out*>* how the parts of the proposal are supposed to fit together.* I must admit that I am completely stumped. In terms of syntax, I thought that I had explained it unambiguously, especially given the examples, which don't leave much to speculation. If a more formal grammar is still desired, I can certainly come up with it, but it doesn't look like it is what is causing issues with understanding here. Correct me if I'm wrong. With respect to how "parts fit together" - I don't understand the problem at all. On one hand, there is a function type definition syntax and semantics taken from Howard's angle brackets proposal - calatogued (athttp://docs.google.com/View?id=ddhp95vd_15gqnv8xqm) as #13 - and modified by me by replacing # with a reference to a pseudo-class java.lang.Function. Then there is a lambda definition syntax and semantics taken from your arrow proposal - catalogued as #5 - and modified by me by dropping -> when body of lambda is expression rather than block, and by prefixing the parenthesized parameter list with an explicit return type. I do believe that those two proposals thus modified and combined make most sense - most "Java-like" in appearance, if you want - in their respective categories. And, so far as I can see, the categories themselves are fully orthogonal, in a sense that one can easily "pick & match" separately. In what way do you expect to see them fit together? Further references: Howard's proposal (which already replaces # with a pseudo-class) - I only referenced the function type part of that, not the lambda definition part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html Your proposal - I only referenced the lambda definition part of that, not the function type part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html Does this help? From jkuhnert at gmail.com Sun Mar 21 19:49:32 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Sun, 21 Mar 2010 22:49:32 -0400 Subject: How about a combo? In-Reply-To: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> References: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> Message-ID: <7926817e1003211949i421041b5p4166faa5716bb4b1@mail.gmail.com> Could be he's the only one nice enough to give feedback when it's desired. You'll notice the number of people responding positively to your proposal that also have Lang design experience is currently 0 vs a lot of well meaning I'm sure but probably not entirely realistic noise. Discusiion is good but I worry that people like you are hogging up so much time "discussing" things that can't possibly happen that we might be missing out on the really good discussions from "informed opinions" - which is what I vaguely remember the "come on down to the poject" announcement mentioning. Sorry if this sounds overtly negative, I'm sure you may be more knowledgeable than me. I just want the best outcome possible. On Sunday, March 21, 2010, Howard Lovatt wrote: > Hi Pavel, > > I don't have a strong preference between my syntax: > > #< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > > > > Your syntax: > > Function< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > > > > Or Gernot Neppert (copied) syntax: > > lambda< *ReturnType,* *ArgumentTypes,* throws *Exceptions* > > > > They are all consistent with current Java (to a much greater degree than > other suggestions), they nest, and you can have arrays of them. Gernot's > syntax is the same as that proposed by JSR 292 for method handles, except > that he uses 'lambda' and they use 'MehodHandle'. (At least I think it is, > JSR 292 is in a state of flux. I have copied John Rose so hopefully he will > be able to enlighten me.) > > The choice between them would really be a matter of style. I chose to use # > for two reasons: > > > ? 1. It was used in the strawman > ? 2. It reminds people that this is not a normal class and that they can't > ? write one of these themselves > > The choice of using round brackets instead of commas was to be consistent > with normal method declarations and was the syntax used in the strawman. > > With regard to Neal's comments (copied); I am like you, at a loss to see why > he cannot understand the proposals. All the proposals, not just those that > use <>, are after all relatively minor syntax variations on each other. > Stefan Schulz (copied) was able to write a grammar for all the proposals, so > clearly he understood them! I didn't find Neal's response to you very > enlightening, he said "He [Howard - Me] invents the concept of varargs > generics just for this purpose" and "To me, his [Howard - Me] proposal looks > like a mess of muddy thinking". ?With regard to "invents the concept of > varargs generics", all the proposals have to deal with a variable number of > arguments and exceptions (that's what methods have) and so does MethodHandle > (which as noted uses <> also). With regard to "muddy thinking", why is > putting <> round some syntax already proposed (strawman) to fix up the > problems of consistency, nesting, and arrays muddled? > > So I don't get why Neal thinks his comments advance the debate about syntax > in general or advance the cause of his preferred syntax, surely lambda dev > is the ideal place for people to discuss syntax suggestions? And it is not > the place "to take your bat home" (good Cricketing term that means "to get > upset") if someone disagrees with your preferred option. > > > ?-- Howard. > > *On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > wrote:* > > *On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter > wrote:* > >>* On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > wrote:*>>**>>* > Other than that, I can't make heads nor tails of this proposal.*>>**>>* Do you refer to the type inference bit, or to the proposal in general?*>>**>>* If the latter, can you be more specific as to what seems troublesome?*>**>* All of it. ?I can't be more specific because I'm having trouble figuring out*>* how the parts of the proposal are supposed to fit together.* > I must admit that I am completely stumped. In terms of syntax, I > thought that I had explained it unambiguously, especially given the > examples, which don't leave much to speculation. If a more formal > grammar is still desired, I can certainly come up with it, but it > doesn't look like it is what is causing issues with understanding > here. Correct me if I'm wrong. > > With respect to how "parts fit together" - I don't understand the > problem at all. > > On one hand, there is a function type definition syntax and semantics > taken from Howard's angle brackets proposal - calatogued > (athttp://Lambda Syntaxes?) as #13 - and > modified by me by replacing # with a reference to a pseudo-class > java.lang.Function. > > Then there is a lambda definition syntax and semantics taken from your > arrow proposal - catalogued as #5 - and modified by me by dropping -> > when body of lambda is expression rather than block, and by prefixing > the parenthesized parameter list with an explicit return type. > > I do believe that those two proposals thus modified and combined make > most sense - most "Java-like" in appearance, if you want - in their > respective categories. And, so far as I can see, the categories > themselves are fully orthogonal, in a sense that one can easily "pick > & match" separately. In what way do you expect to see them fit > together? > > Further references: > > Howard's proposal (which already replaces # with a pseudo-class) - I > only referenced the function type part of that, not the lambda > definition part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html > > Your proposal - I only referenced the lambda definition part of that, > not the function type > part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html > > > Does this help? > > From howard.lovatt at gmail.com Sun Mar 21 21:09:37 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 22 Mar 2010 15:09:37 +1100 Subject: How about a combo? Message-ID: <3dd3f56a1003212109v5e41aa1dr3cc9beaf1cc9e34a@mail.gmail.com> Jesse, The response, see below, from Josh Bloch would appear to me to be more productive. It gives specific issues with his opinion, it doesn't make bizarre claims about how difficult the proposal is to understand and/or implement, and the general tone is one of reason. Josh Bloch's comments I would have thought are much more likely to convince people to come round to his point of view. -- Howard. Response from Joshua Bloch: My two cents: #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = new #< #( #< R( A ) throws E > l, A a ) >( l.( a ) ); Nesting is nice, but: - The angle brackets will remind people of generics, which won't make them happy. - Angle brackets are a poor man's parentheses, because they do double duty as unmatched operators (less than and greater than). - The pound-sign+left-angle-bracket combo (#<) isn't exactly easy on the eyes. - The new keyword will be viewed as exactly the kind of boilerplate that this effort was designed to eliminate. I do think it makes sense to explore new syntax proposals, but I'm not sure I like this one better than the one that's currently on the table. Josh From jkuhnert at gmail.com Sun Mar 21 21:32:47 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Mon, 22 Mar 2010 00:32:47 -0400 Subject: How about a combo? In-Reply-To: <3dd3f56a1003212109v5e41aa1dr3cc9beaf1cc9e34a@mail.gmail.com> References: <3dd3f56a1003212109v5e41aa1dr3cc9beaf1cc9e34a@mail.gmail.com> Message-ID: <7926817e1003212132v56af6e5cieda4a2b6f45915e3@mail.gmail.com> Again, someone was being nice and giving a very detailed response. The end result is still the same. You are clearly not grasping just how far off from a sane reality your ideas look and feel to even uninformed people like myself. No analogy is coming to mind to drive this point home but just think for a second who these people giving you feedback are and what their collective professional knowledge might indicate. It is one thing to be missing knowledge and quite another to ignore this in the face of overwhelming evidence to the contrary. Your proposals so far have looked overly complex / are not easy to follow / much too verbose when you look at the big picture goals of what the objective is. You say your ideas "feel" more like java in the context of opposing ideas from people who can actually claim to have defined some of what that "feel" is. I dont know what else to say. This is serious business with big consequences and being nice and doing lots of hand holding may not be appropriate in this particular forum. Do you want a rookie intern performing your heart bypass or a seasoned old crochety surgeon? There, I found one. =) On Monday, March 22, 2010, Howard Lovatt wrote: > Jesse, > The response, see below, from Josh Bloch would appear to me to be more productive. It gives specific issues with his opinion, it doesn't make?bizarre?claims about how difficult the proposal is to understand and/or implement, and the general tone is one of reason. Josh Bloch's comments I would have thought are much more likely to convince people to come round to his point of view. > > > ?-- Howard. > > Response from Joshua Bloch:My two cents: > > #< #< R() throws E >( #< R( A ) throws E >, A ) > curry = > new #< #( #< R( A ) throws E > l, A a ) >( l.( a ) ); > > Nesting is nice, but: > > - The angle brackets will remind people of generics, which won't make > them happy. > - Angle brackets are a poor man's parentheses, because they do double > duty as unmatched operators (less than and greater than). > - The pound-sign+left-angle-bracket combo (#<) isn't exactly easy on the > eyes. > - The new keyword will be viewed as exactly the kind of boilerplate that > this effort was designed to eliminate. > > I do think it makes sense to explore new syntax proposals, but I'm not sure > I like this one better than the one that's currently on the table. > > Josh > From neal at gafter.com Sun Mar 21 23:19:05 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 21 Mar 2010 23:19:05 -0700 Subject: Not Dead Yet (was: MethodHandle vs function types) In-Reply-To: <3dd3f56a1002241253n413f1747pa16ae898b06f5fb5@mail.gmail.com> References: <3dd3f56a1002241253n413f1747pa16ae898b06f5fb5@mail.gmail.com> Message-ID: <15e8b9d21003212319x2d59d7btd4931baca47c3325@mail.gmail.com> On Wed, Feb 24, 2010 at 1:53 PM, Howard Lovatt wrote: > Neal Gafter Said > > Approach (1) doesn't work for various reasons. As we've already seen by > the > > failure of Howard Lovatt's attempt to reify function types, we must > preserve > > reference identity for all widening reference conversions. > > I would say this is overstating the problems. ... I am still considering > other > options. > > > Therefore I would say, with apologies to Monty Python, that reified > lambdas are "not dead yet". > Would you say they're dead now that you've had a month to study the problem? From reinier at zwitserloot.com Sun Mar 21 23:48:36 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 22 Mar 2010 07:48:36 +0100 Subject: How about a combo? In-Reply-To: <7926817e1003211949i421041b5p4166faa5716bb4b1@mail.gmail.com> References: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> <7926817e1003211949i421041b5p4166faa5716bb4b1@mail.gmail.com> Message-ID: <560fb5ed1003212348xe8b8594y28b76fe36d25183@mail.gmail.com> I think Howard might be on to something, so make that one. Also, I don't think you have the qualifications to decide that what Howard posted was noise, but your half-baked defense of Neal's clearly argumentative "I don't understand anything" posts isn't. --Reinier Zwitserloot On Mon, Mar 22, 2010 at 3:49 AM, Jesse Kuhnert wrote: > Could be he's the only one nice enough to give feedback when it's desired. > > You'll notice the number of people responding positively to your > proposal that also have Lang design experience is currently 0 vs a lot > of well meaning I'm sure but probably not entirely realistic noise. > > Discusiion is good but I worry that people like you are hogging up so > much time "discussing" things that can't possibly happen that we might > be missing out on the really good discussions from "informed opinions" > - which is what I vaguely remember the "come on down to the poject" > announcement mentioning. > > Sorry if this sounds overtly negative, I'm sure you may be more > knowledgeable than me. I just want the best outcome possible. > > On Sunday, March 21, 2010, Howard Lovatt wrote: > > Hi Pavel, > > > > I don't have a strong preference between my syntax: > > > > #< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > > > > > > > Your syntax: > > > > Function< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > > > > > > > Or Gernot Neppert (copied) syntax: > > > > lambda< *ReturnType,* *ArgumentTypes,* throws *Exceptions* > > > > > > > They are all consistent with current Java (to a much greater degree than > > other suggestions), they nest, and you can have arrays of them. Gernot's > > syntax is the same as that proposed by JSR 292 for method handles, except > > that he uses 'lambda' and they use 'MehodHandle'. (At least I think it > is, > > JSR 292 is in a state of flux. I have copied John Rose so hopefully he > will > > be able to enlighten me.) > > > > The choice between them would really be a matter of style. I chose to use > # > > for two reasons: > > > > > > 1. It was used in the strawman > > 2. It reminds people that this is not a normal class and that they > can't > > write one of these themselves > > > > The choice of using round brackets instead of commas was to be consistent > > with normal method declarations and was the syntax used in the strawman. > > > > With regard to Neal's comments (copied); I am like you, at a loss to see > why > > he cannot understand the proposals. All the proposals, not just those > that > > use <>, are after all relatively minor syntax variations on each other. > > Stefan Schulz (copied) was able to write a grammar for all the proposals, > so > > clearly he understood them! I didn't find Neal's response to you very > > enlightening, he said "He [Howard - Me] invents the concept of varargs > > generics just for this purpose" and "To me, his [Howard - Me] proposal > looks > > like a mess of muddy thinking". With regard to "invents the concept of > > varargs generics", all the proposals have to deal with a variable number > of > > arguments and exceptions (that's what methods have) and so does > MethodHandle > > (which as noted uses <> also). With regard to "muddy thinking", why is > > putting <> round some syntax already proposed (strawman) to fix up the > > problems of consistency, nesting, and arrays muddled? > > > > So I don't get why Neal thinks his comments advance the debate about > syntax > > in general or advance the cause of his preferred syntax, surely lambda > dev > > is the ideal place for people to discuss syntax suggestions? And it is > not > > the place "to take your bat home" (good Cricketing term that means "to > get > > upset") if someone disagrees with your preferred option. > > > > > > -- Howard. > > > > *On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > > wrote:* > > > > *On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter > > wrote:* > > > >>* On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev http://mail.openjdk.java.net/mailman/listinfo/lambda-dev>> wrote:*>>**>>* > > Other than that, I can't make heads nor tails of this proposal.*>>**>>* Do > you refer to the type inference bit, or to the proposal in general?*>>**>>* > If the latter, can you be more specific as to what seems troublesome?*>**>* > All of it. I can't be more specific because I'm having trouble figuring > out*>* how the parts of the proposal are supposed to fit together.* > > I must admit that I am completely stumped. In terms of syntax, I > > thought that I had explained it unambiguously, especially given the > > examples, which don't leave much to speculation. If a more formal > > grammar is still desired, I can certainly come up with it, but it > > doesn't look like it is what is causing issues with understanding > > here. Correct me if I'm wrong. > > > > With respect to how "parts fit together" - I don't understand the > > problem at all. > > > > On one hand, there is a function type definition syntax and semantics > > taken from Howard's angle brackets proposal - calatogued > > (athttp://Lambda Syntaxes < > http://docs.google.com/View?id=ddhp95vd_15gqnv8xqm>) as #13 - and > > modified by me by replacing # with a reference to a pseudo-class > > java.lang.Function. > > > > Then there is a lambda definition syntax and semantics taken from your > > arrow proposal - catalogued as #5 - and modified by me by dropping -> > > when body of lambda is expression rather than block, and by prefixing > > the parenthesized parameter list with an explicit return type. > > > > I do believe that those two proposals thus modified and combined make > > most sense - most "Java-like" in appearance, if you want - in their > > respective categories. And, so far as I can see, the categories > > themselves are fully orthogonal, in a sense that one can easily "pick > > & match" separately. In what way do you expect to see them fit > > together? > > > > Further references: > > > > Howard's proposal (which already replaces # with a pseudo-class) - I > > only referenced the function type part of that, not the lambda > > definition part: > http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html > > > > Your proposal - I only referenced the lambda definition part of that, > > not the function type > > part: > http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html > > > > > > Does this help? > > > > > > From int19h at gmail.com Sun Mar 21 23:55:03 2010 From: int19h at gmail.com (Pavel Minaev) Date: Mon, 22 Mar 2010 00:55:03 -0600 Subject: How about a combo? In-Reply-To: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> References: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> Message-ID: On Sun, Mar 21, 2010 at 8:24 PM, Howard Lovatt wrote: > I don't have a strong preference between my syntax: > > #< ReturnType( ArgumentTypes ) throws Exceptions > > > Your syntax: > > Function > > Or Gernot Neppert (copied) syntax: > > lambda > > They are all consistent with current Java (to a much greater degree than > other suggestions), they nest, and you can have arrays of them. Gernot's > syntax is the same as that proposed by JSR 292 for method handles, except > that he uses 'lambda' and they use 'MehodHandle'. (At least I think it is, > JSR 292 is in a state of flux. I have copied John Rose so?hopefully?he will > be able to enlighten me.) > The choice between them would really be a matter of style. I agree that the differences are really minor between those styles, and I also agree with your reasoning as to why it is more consistent with other existing Java constructs. By the way, "mine" syntax is really yours :) - I do not think that me renaming "java.lang.Lambda" to "java.lang.Function" constitutes any real contribution. >I chose to use # > for two reasons: > > It was used in the strawman > It reminds people that this is not a normal class and that they can't write > one of these themselves My sole objection to # - which, actually, stretches out to other proposals that use magic symbols, as well - is that it is "unnaturally looking" in context of Java as it currently stands. It breaks the long-standing assumption that type references always begin with an alphanumeric identifier or keyword, and never with a special character ("int", "java.lang.String[]", "List" etc) So far the only characters used in type references are: <>[].,?& - and they all come after/between identifiers, not before them. Of course, it's not something that was deliberately designed into the language, but nonetheless, it does contribute to its existing look and feel. I suspect (just a wild guess, of course) that it was a subconscious factor in Joshua's assessment of several proposals as "non Java-like". I do actually share that feeling - personally, when I see something like: #<...> x; or: #(...) x; it just doesn't "click" for me as a variable declaration, because the leftmost production simply doesn't look like a type "should" look in Java. Oh, and I would very much prefer a keyword ("lambda" or a different one, doesn't matter) there over a "magic class name", but there's no way to use one without breaking backwards compatibility, so far as I can see. Even if using context keywords (a la C#'s "get" and "set"), no reasonable syntax for function types that I've seen on this mailing list so far would allow for a context keyword that is entirely unambiguous. Of course, this all is very subjective. I think, however, that there is a real issue there, in that you can't just come with any random syntax - no matter how logical, or convenient to parse - and have developers like it and use it readily. To some extent, it also has to be familiar. If it's a new concept, this means reinterpreting as much of it as possible in terms of concepts that are already there, and for those parts which really are new, thinking of how the established patterns can be logically extended to cover them. I do not claim that the proposal above is the solution (or even a solution) to this problem. But I think that this is something that really should be seriously considered when evaluating proposals, alongside readability, lack of syntactic ambiguity, and self-consistency. From scolebourne at joda.org Mon Mar 22 05:05:05 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Mon, 22 Mar 2010 09:05:05 -0300 Subject: Options for accessing local variables In-Reply-To: <4BA5C4C0.5030709@adres.pl> References: <4b4f45e01003200505o2ce0be51h874ea04ef812f42@mail.gmail.com> <15e8b9d21003200911tc224je5b1fa76d0e4513e@mail.gmail.com> <4BA5C4C0.5030709@adres.pl> Message-ID: <4b4f45e01003220505l5c77d3c8r48e62d0b78f5a8df@mail.gmail.com> I?m on holiday, so the original email and this one were v. quick. If someone wants to takle the original and fix or extend I?d be happy . Stephen On 21 March 2010 04:03, Artur Biesiadowski wrote: > Hello > > One more missing - > > Variables are copied on construction AND final inside lambda. They can > be modified afterwards in calling scope. > > ?int[] total = new int[1]; > ?Utils.each(list, #(String str) { total[0] += str.length() }); > > I think it would be nice to extend the examples with modification of > total in calling scope - it is not always clear if variables has to be > effectively final or not. > > Regards, > Artur Biesiadowski > > > Neal Gafter wrote: >> You failed to list the choices made in CfJ, the draft specification, and the >> strawman: >> >> CfJ) Full access to local variables, but a warning if a variable is accessed >> when not annotated and not effectively final. >> Draft) Access to local variables only if effectively final. >> Strawman) Full access to local variables if effectively final or a keyword >> appears on the variable declaration. >> >> Cheers, >> Neal >> >> On Sat, Mar 20, 2010 at 5:05 AM, Stephen Colebourne wrote: >> > [...] > > From jkuhnert at gmail.com Mon Mar 22 06:30:56 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Mon, 22 Mar 2010 09:30:56 -0400 Subject: How about a combo? In-Reply-To: <560fb5ed1003212348xe8b8594y28b76fe36d25183@mail.gmail.com> References: <3dd3f56a1003211924m20df68d4m49b9514f329f7be4@mail.gmail.com> <7926817e1003211949i421041b5p4166faa5716bb4b1@mail.gmail.com> <560fb5ed1003212348xe8b8594y28b76fe36d25183@mail.gmail.com> Message-ID: <7926817e1003220630h232af299n927c178d4319235d@mail.gmail.com> I'm sure I'll be corrected by someone then, assuming I'm wrong. On Monday, March 22, 2010, Reinier Zwitserloot wrote: > I think Howard might be on to something, so make that one. Also, I don't think you have the qualifications to decide that what Howard posted was noise, but your half-baked defense of Neal's clearly argumentative "I don't understand anything" posts isn't. > --Reinier Zwitserloot > > > > On Mon, Mar 22, 2010 at 3:49 AM, Jesse Kuhnert wrote: > > Could be he's the only one nice enough to give feedback when it's desired. > > You'll notice the number of people responding positively to your > proposal that also have Lang design experience is currently 0 vs a lot > of well meaning I'm sure but probably not entirely realistic noise. > > Discusiion is good but I worry that people like you are hogging up so > much time "discussing" things that can't possibly happen that we might > be missing out on the really good discussions from "informed opinions" > - which is what I vaguely remember the "come on down to the poject" > announcement mentioning. > > Sorry if this sounds overtly negative, I'm sure you may be more > knowledgeable than me. I just want the best outcome possible. > > On Sunday, March 21, 2010, Howard Lovatt wrote: >> Hi Pavel, >> >> I don't have a strong preference between my syntax: >> >> #< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > >> >> >> Your syntax: >> >> Function< *ReturnType*( *ArgumentTypes* ) throws *Exceptions* > >> >> >> Or Gernot Neppert (copied) syntax: >> >> lambda< *ReturnType,* *ArgumentTypes,* throws *Exceptions* > >> >> >> They are all consistent with current Java (to a much greater degree than >> other suggestions), they nest, and you can have arrays of them. Gernot's >> syntax is the same as that proposed by JSR 292 for method handles, except >> that he uses 'lambda' and they use 'MehodHandle'. (At least I think it is, >> JSR 292 is in a state of flux. I have copied John Rose so hopefully he will >> be able to enlighten me.) >> >> The choice between them would really be a matter of style. I chose to use # >> for two reasons: >> >> >> ?? 1. It was used in the strawman >> ?? 2. It reminds people that this is not a normal class and that they can't >> ?? write one of these themselves >> >> The choice of using round brackets instead of commas was to be consistent >> with normal method declarations and was the syntax used in the strawman. >> >> With regard to Neal's comments (copied); I am like you, at a loss to see why >> he cannot understand the proposals. All the proposals, not just those that >> use <>, are after all relatively minor syntax variations on each other. >> Stefan Schulz (copied) was able to write a grammar for all the proposals, so >> clearly he understood them! I didn't find Neal's response to you very >> enlightening, he said "He [Howard - Me] invents the concept of varargs >> generics just for this purpose" and "To me, his [Howard - Me] proposal looks >> like a mess of muddy thinking". ?With regard to "invents the concept of >> varargs generics", all the proposals have to deal with a variable number of >> arguments and exceptions (that's what methods have) and so does MethodHandle >> (which as noted uses <> also). With regard to "muddy thinking", why is >> putting <> round some syntax already proposed (strawman) to fix up the >> problems of consistency, nesting, and arrays muddled? >> >> So I don't get why Neal thinks his comments advance the debate about syntax >> in general or advance the cause of his preferred syntax, surely lambda dev >> is the ideal place for people to discuss syntax suggestions? And it is not >> the place "to take your bat home" (good Cricketing term that means "to get >> upset") if someone disagrees with your preferred option. >> >> >> ?-- Howard. >> >> *On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > > wrote:* >> >> *On Fri, Mar 19, 2010 at 7:49 PM, Neal Gafter > > wrote:* >> >>>* On Fri, Mar 19, 2010 at 5:53 PM, Pavel Minaev > wrote:*>>**>>* > Other than that, I can't make heads nor tails of this proposal.*>>**>>* Do > (athttp://Lambda Syntaxes?>) as #13 - and >> modified by me by replacing # with a reference to a pseudo-class >> java.lang.Function. >> >> Then there is a lambda definition syntax and semantics taken from your >> arrow proposal - catalogued as #5 - and modified by me by dropping -> >> when body of lambda is expression rather than block, and by prefixing >> the parenthesized parameter list with an explicit return type. >> >> I do believe that those two proposals thus modified and combined make >> most sense - most "Java-like" in appearance, if you want - in their >> respective categories. And, so far as I can see, the categories >> themselves are fully orthogonal, in a sense that one can easily "pick >> & match" separately. In what way do you expect to see them fit >> together? >> >> Further references: >> >> Howard's proposal (which already replaces # with a pseudo-class) - I >> only referenced the function type part of that, not the lambda >> definition part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-March/001135.html >> >> Your proposal - I only referenced the lambda definition part of that, >> not the function type >> part:http://mail.openjdk.java.net/pipermail/lambda-dev/2010-February/000610.html >> >> >> Does this help? >> >> > > > > From howard.lovatt at gmail.com Mon Mar 29 02:36:45 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 29 Mar 2010 20:36:45 +1100 Subject: New Message-ID: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> A number of people have commented about using new for lambdas, there are at least 4 good reasons to use new: 1. It is what the rest of Java uses, e.g.: List list = new ArrayList(); # lambda = new #(42); 2. It is compatible with the diamond operator from Coin (assuming <> are used), e.g.: List list = new ArrayList<>(); # lambda = new #<>(42); 3. The main argument for not using new is that the compiler can 'lift' the lambda to be static if it doesn't access any instance fields or local variables. However this type of optimization has a poor history in Java, think String interning and copying of static fields. In Java a JVM optimization has proven much more successful than a compiler optimization. Hence using new, which would allow a JVM optimization but prevent a compiler optimization, is the best choice. 4. There are times when you want to control instantiation, consider a GUI application that uses a custom queue that checks for double entries (e.g. caused by an impatient user multiply single clicking - I do this!), the job queue might be: class Jobs extends LinkedBlockingDeque< # > { @Override public void put( final # e ) { if ( !peekLast().equals( e ) ) { super.put( e ); } } } Then you might implement the main class of an application as: class GUI { private static final Jobs jobs = new Jobs(); private static final # FRAME_TO_FRONT = new #<> { ... }; static void frameClicked() { jobs.put( FRAME_TO_FRONT ); } static void fileMenuClicked() { final # toggleFileMenu = new #<> { ... }; jobs.put( toggleFileMenu ); } ... } Note how control over creation is critical, multiple frameClicked() calls can be safely eliminated but multiple fileMenuClicked() calls cannot because these toggle the menu. -- Howard. PS # could be substituted for lambda, Lambda, Function, etc. From forax at univ-mlv.fr Mon Mar 29 02:50:31 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 29 Mar 2010 11:50:31 +0200 Subject: New In-Reply-To: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> Message-ID: <4BB077E7.4070207@univ-mlv.fr> Le 29/03/2010 11:36, Howard Lovatt a ?crit : > A number of people have commented about using new for lambdas, there are at > least 4 good reasons to use new: > > 1. It is what the rest of Java uses, e.g.: > > List list = new ArrayList(); > # lambda = new #(42); > String s ="foo"; > 2. It is compatible with the diamond operator from Coin (assuming<> are > used), e.g.: > > List list = new ArrayList<>(); > # lambda = new #<>(42); > The diamond operator doesn't work with primitive types. [...] R?mi From mthornton at optrak.co.uk Mon Mar 29 02:53:15 2010 From: mthornton at optrak.co.uk (Mark Thornton) Date: Mon, 29 Mar 2010 10:53:15 +0100 Subject: New In-Reply-To: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> Message-ID: <4BB0788B.8090302@optrak.co.uk> Howard Lovatt wrote: > 3. The main argument for not using new is that the compiler can 'lift' the > lambda to be static if it doesn't access any instance fields or local > variables. However this type of optimization has a poor history in Java, > think String interning and copying of static fields. In Java a JVM > optimization has proven much more successful than a compiler optimization. > Hence using new, which would allow a JVM optimization but prevent a compiler > optimization, is the best choice. > On the other hand the JVM optimisations (escape analysis) to reduce heap allocation have been "coming soon" for more years than I care to remember. Mark From peter.levart at marand.si Mon Mar 29 03:22:24 2010 From: peter.levart at marand.si (Peter Levart) Date: Mon, 29 Mar 2010 12:22:24 +0200 Subject: New In-Reply-To: <4BB0788B.8090302@optrak.co.uk> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> Message-ID: <201003291222.24898.peter.levart@marand.si> On 03/29/10, Mark Thornton wrote: > Howard Lovatt wrote: > > 3. The main argument for not using new is that the compiler can 'lift' the > > lambda to be static if it doesn't access any instance fields or local > > variables. However this type of optimization has a poor history in Java, > > think String interning and copying of static fields. I never had any trouble as a consequence of interned Strings. What do you mean by "copying of static fields"? > > In Java a JVM > > optimization has proven much more successful than a compiler optimization. > > Hence using new, which would allow a JVM optimization but prevent a compiler > > optimization, is the best choice. > > > On the other hand the JVM optimisations (escape analysis) to reduce heap > allocation have been "coming soon" for more years than I care to remember. > But it has arrived, hasn't it? It's in JDK 1.6.0_14 (check -XX:+DoEscapeAnalysis)... The thing to note is that such escape analysis is only effective if it can positively determine that an object instance (constructed with new) can not escape local computation. If someone wanted to use escape analysis to optimize instantiation of lambdas then such analysis could only be effective if the instantiation of lambda and invocation of it was peformed as part of the same local computation. For example (in term's of Lowatt's syntax): { # lambda = new #(42); assert 42 == lambda.(); } I think that such usages are useless (why creating a lambda in order to only invoke it afterwards). Other usages involve passing lambda instance to some method. In those cases escape analysis can't help if those methods are not aggresively inlined. I think that relying on such situations would render optimization in case of lambdas practically non-effective. I think that specifying lambda identity by not specifying it is so far the most promissing direction to enable optimizations. This unfortunately conflicts with "new" semantics but I don't find this as a drawback for specifying a usefull syntax that doesn't include "new". Regards, Peter From howard.lovatt at gmail.com Mon Mar 29 03:26:28 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 29 Mar 2010 21:26:28 +1100 Subject: New In-Reply-To: <4BB0788B.8090302@optrak.co.uk> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> Message-ID: <3dd3f56a1003290326u300a47vd59d45af2848c1b3@mail.gmail.com> I think this is a two sided argument, it has proved difficult to eliminate object creation because it is tricky to do without gotchas. Take a look at my point 4 example to see how hard that would be for the compiler to get right (e.g. when Jobs is in a library and your program GUI doesn't even compile Jobs). On 29 March 2010 20:53, Mark Thornton wrote: > Howard Lovatt wrote: > >> 3. The main argument for not using new is that the compiler can 'lift' the >> lambda to be static if it doesn't access any instance fields or local >> variables. However this type of optimization has a poor history in Java, >> think String interning and copying of static fields. In Java a JVM >> optimization has proven much more successful than a compiler optimization. >> Hence using new, which would allow a JVM optimization but prevent a >> compiler >> optimization, is the best choice. >> >> > On the other hand the JVM optimisations (escape analysis) to reduce heap > allocation have been "coming soon" for more years than I care to remember. > > Mark > > -- -- Howard. From mthornton at optrak.co.uk Mon Mar 29 03:26:39 2010 From: mthornton at optrak.co.uk (Mark Thornton) Date: Mon, 29 Mar 2010 11:26:39 +0100 Subject: New In-Reply-To: <201003291222.24898.peter.levart@marand.si> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> Message-ID: <4BB0805F.8060506@optrak.co.uk> Peter Levart wrote: > > On 03/29/10, Mark Thornton wrote: > > > On the other hand the JVM optimisations (escape analysis) to reduce > heap > > > allocation have been "coming soon" for more years than I care to > remember. > > > > > But it has arrived, hasn't it? It's in JDK 1.6.0_14 (check > -XX:+DoEscapeAnalysis)... > Disabled again in update 18 :-( Mark From howard.lovatt at gmail.com Mon Mar 29 03:39:08 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 29 Mar 2010 21:39:08 +1100 Subject: New In-Reply-To: <201003291222.24898.peter.levart@marand.si> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> Message-ID: <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> Comments in line On 29 March 2010 21:22, Peter Levart wrote: > On 03/29/10, Mark Thornton wrote: > > > Howard Lovatt wrote: > > > > 3. The main argument for not using new is that the compiler can 'lift' > the > > > > lambda to be static if it doesn't access any instance fields or local > > > > variables. However this type of optimization has a poor history in > Java, > > > > think String interning and copying of static fields. > > I never had any trouble as a consequence of interned Strings. > Java Puzzlers 13 & 62 are to do with interned Strings, so I would have thought it does occur. I have corrected programs that have used == when they should have used equals (they passed the unit tests because of interning). This group has also commented on the undesirability of Integer interning for some values and not others. > What do you mean by "copying of static fields"? > Java Puzzlers 93 is about this one > > > In Java a JVM > > > > optimization has proven much more successful than a compiler > optimization. > > > > Hence using new, which would allow a JVM optimization but prevent a > compiler > > > > optimization, is the best choice. > > > > > > > On the other hand the JVM optimisations (escape analysis) to reduce heap > > > allocation have been "coming soon" for more years than I care to > remember. > > > > > But it has arrived, hasn't it? It's in JDK 1.6.0_14 (check - > XX:+DoEscapeAnalysis)... > > The thing to note is that such escape analysis is only effective if it can > positively determine that an object instance (constructed with new) can not > escape local computation. If someone wanted to use escape analysis to > optimize instantiation of lambdas then such analysis could only be effective > if the instantiation of lambda and invocation of it was peformed as part of > the same local computation. For example (in term's of Lowatt's syntax): > > { > > # lambda = new #(42); > > assert 42 == lambda.(); > > } > > I think that such usages are useless (why creating a lambda in order to > only invoke it afterwards). > > Other usages involve passing lambda instance to some method. In those cases > escape analysis can't help if those methods are not aggresively inlined. I > think that relying on such situations would render optimization in case of > lambdas practically non-effective. > > I think that specifying lambda identity by not specifying it is so far the > most promissing direction to enable optimizations. This unfortunately > conflicts with "new" semantics but I don't find this as a drawback for > specifying a usefull syntax that doesn't include "new". > > Regards, Peter > > Just a note. I wouldn't suggest escape analysis as the appropriate optimization. It would need to be a new optimization. -- -- Howard. From peter.levart at marand.si Mon Mar 29 03:56:12 2010 From: peter.levart at marand.si (Peter Levart) Date: Mon, 29 Mar 2010 12:56:12 +0200 Subject: New In-Reply-To: <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> Message-ID: <201003291256.12407.peter.levart@marand.si> On 03/29/10, Howard Lovatt wrote: > Just a note. I wouldn't suggest escape analysis as the appropriate > optimization. It would need to be a new optimization. > Do you have any idea how such optimization should work? Regards, Peter From peter.levart at marand.si Mon Mar 29 04:20:23 2010 From: peter.levart at marand.si (Peter Levart) Date: Mon, 29 Mar 2010 13:20:23 +0200 Subject: New In-Reply-To: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> Message-ID: <201003291320.23725.peter.levart@marand.si> On 03/29/10, Howard Lovatt wrote: > 2. It is compatible with the diamond operator from Coin (assuming <> are > used), e.g.: > > List list = new ArrayList<>(); > # lambda = new #<>(42); > How would diamond operator work for this example: #int(int, int) add = #(int a, int b)(a+b); Peter From opinali at gmail.com Mon Mar 29 04:46:04 2010 From: opinali at gmail.com (Osvaldo Doederlein) Date: Mon, 29 Mar 2010 08:46:04 -0300 Subject: New In-Reply-To: <201003291256.12407.peter.levart@marand.si> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <201003291256.12407.peter.levart@marand.si> Message-ID: I have an idea to settle this debate and avoid further fight: a design that depends on advanced optimization (either EA or some new one) should only be considered as soon as we have, at least in alpha stage, said optimization in the JDK7 project. And by "we have it" I imply that we also have specific benchmarks that shows that the optimization does indeed eliminate the cost it should. So, I'm not content with a microbenchmarks of non-lambda code (e.g. en enhanced-for loop of collections that needs scalar replacement of Iterator objects); I want to see benchmarks that show a well-representative assorting of lambda code, demonstrating that the optimizer will typically eliminate extra allocation imposed by the 'new'. [EA & stack allocation is already available; and we don't need a working prototype of a compiler for the lambda proposal as it's possible to manually write the same desugared code that would be emitted by such compiler. So, whoever believes in the lemma "let's make a mess - the JIT will clean up after us") must only write some benchmark code.] P.S.: EA & stack allocation are coming back in JDK 6u20, which is now in beta and is planned to ship on June. It seems that EA is in enough good shape as they're enabling it by default. OTOH, it's still exclusive to HotSpot Server, and I have little hope that the Client compiler will get this optimization any time soon. So I reinforce my negative vote (FWIW) on any important language design that will be good only for server-side apps - lambdas is a proposal for the next JavaSE platform, not for the next JavaEE platform. A+ Osvaldo 2010/3/29 Peter Levart > On 03/29/10, Howard Lovatt wrote: > > Just a note. I wouldn't suggest escape analysis as the appropriate > > optimization. It would need to be a new optimization. > > > > Do you have any idea how such optimization should work? > > Regards, Peter > > From jjb at google.com Mon Mar 29 08:00:31 2010 From: jjb at google.com (Joshua Bloch) Date: Mon, 29 Mar 2010 08:00:31 -0700 Subject: New In-Reply-To: <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> Message-ID: <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> Howard, On Mon, Mar 29, 2010 at 3:39 AM, Howard Lovatt wrote: This group has also commented on the undesirability of Integer interning for some values and not others. I don't think that's the problem so much as the fact that the spec mandates which values must be interned. This causes people to write unreadable and unmaintainable programs that take advantage of those guarantees. I with the JLS had merely suggested that implementations might want to cache and reuse common values as a quality-of-service issue. So I see this as a case of overspecification, rather that an inherently bad idea. As I said a while back, I believe the same behavior is appropriate for lambdas: the specification should not mandate the creation of an object each time a lambda expression is evaluate, and should note (using non-normative text), that implementers should avoid creating such objects when it results in improved performance. Regarding the desirability of using the "new" keyword for lambdas (a purely syntactic decision): Even if each evaluation of a lambda expression did result in the creation of a new object, a primary raison d'etre for lambdas in Java is economy of expression. The "new" keyword (preceded and followed by a space) is detrimental to that goal. Josh From neal at gafter.com Mon Mar 29 09:14:06 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 29 Mar 2010 12:14:06 -0400 Subject: New In-Reply-To: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> Message-ID: <15e8b9d21003290914h75d37d60q2806bd11e3d1361d@mail.gmail.com> On Mon, Mar 29, 2010 at 5:36 AM, Howard Lovatt wrote: > A number of people have commented about using new for lambdas, there are at > least 4 good reasons to use new: > > 1. It is what the rest of Java uses, e.g.: > > List list = new ArrayList(); > # lambda = new #(42); > Only for object creation. A lambda expression is not a mechanism for creating an object, so being consistent in this area would be a disadvantage. > 2. It is compatible with the diamond operator from Coin (assuming <> are > used), e.g.: > > List list = new ArrayList<>(); > # lambda = new #<>(42); > Given that they have nothing whatsoever to do with each other, that's a disadvantage too. > 3. The main argument for not using new is that the compiler can 'lift' the > lambda to be static if it doesn't access any instance fields or local > variables. However this type of optimization has a poor history in Java,... > This isn't an optimization. The compiler needs to translate each lambda expression into a reference to a suitable object, and select an appropriate lifetime for that object. The compiler should not intentionally generate bad code in the hope that it will be improved later. ... Note how control over creation is critical, multiple frameClicked() > calls > can be safely eliminated but multiple fileMenuClicked() calls cannot > because > these toggle the menu. > Actually, in your example control over creation (of the function object) is not at all critical, because the creation time is not visible to the program. I agree that multiple fileMenuClicked() calls cannot be eliminated; that is because it has a side-effect "jobs.put(toggleFileMenu);" having nothing at all to do with lambda creation. The (hidden) creation time of the function object designated by the lambda has no impact on the program's semantics. From alex.buckley at oracle.com Mon Mar 29 14:07:31 2010 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 29 Mar 2010 14:07:31 -0700 Subject: New In-Reply-To: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> Message-ID: <4BB11693.4090703@oracle.com> The draft spec in the OpenJDK Lambda project will continue to avoid 'new' in the denotation of a lambda expression. Let me remind everyone that a spec from this project is likely to be merely a starting point for a JSR Expert Group. The Expert Group members may or may not review the mailing list archives of this project, so endless syntax discussions here are somewhat futile. Before anyone asks, I have no information about the formation or schedule of such a JSR. Alex On 3/29/2010 2:36 AM, Howard Lovatt wrote: > A number of people have commented about using new for lambdas, there are at > least 4 good reasons to use new: > > 1. It is what the rest of Java uses, e.g.: > > List list = new ArrayList(); > # lambda = new #(42); > > 2. It is compatible with the diamond operator from Coin (assuming <> are > used), e.g.: > > List list = new ArrayList<>(); > # lambda = new #<>(42); > > 3. The main argument for not using new is that the compiler can 'lift' the > lambda to be static if it doesn't access any instance fields or local > variables. However this type of optimization has a poor history in Java, > think String interning and copying of static fields. In Java a JVM > optimization has proven much more successful than a compiler optimization. > Hence using new, which would allow a JVM optimization but prevent a compiler > optimization, is the best choice. > > 4. There are times when you want to control instantiation, consider a GUI > application that uses a custom queue that checks for double entries (e.g. > caused by an impatient user multiply single clicking - I do this!), the job > queue might be: > > class Jobs extends LinkedBlockingDeque< # > { > @Override public void put( final # e ) { > if ( !peekLast().equals( e ) ) { super.put( e ); } > } > } > > Then you might implement the main class of an application as: > > class GUI { > private static final Jobs jobs = new Jobs(); > > private static final # FRAME_TO_FRONT = new #<> { ... }; > static void frameClicked() { jobs.put( FRAME_TO_FRONT ); } > > static void fileMenuClicked() { > final # toggleFileMenu = new #<> { ... }; > jobs.put( toggleFileMenu ); > } > > ... > } > > Note how control over creation is critical, multiple frameClicked() calls > can be safely eliminated but multiple fileMenuClicked() calls cannot because > these toggle the menu. > > -- Howard. > > PS # could be substituted for lambda, Lambda, Function, etc. > From howard.lovatt at gmail.com Mon Mar 29 18:31:00 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 30 Mar 2010 12:31:00 +1100 Subject: New In-Reply-To: <201003291256.12407.peter.levart@marand.si> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <201003291256.12407.peter.levart@marand.si> Message-ID: <3dd3f56a1003291831i73776739scef4a3351cfe9cf9@mail.gmail.com> It is not easy to do this optimization, take a look at my example in point 4. I can't see how the compiler can do this at all. The JVM might be able to do it. The obvious checks are that it doesn't access this or any non-final local variables, but in addition you need to check that == and != are never used. I would suggest that the optimization is only practical once the JVM has in-lined all the method calls, then it could check if == or != are used. On 29 March 2010 21:56, Peter Levart wrote: > On 03/29/10, Howard Lovatt wrote: > > Just a note. I wouldn't suggest escape analysis as the appropriate > > optimization. It would need to be a new optimization. > > > > Do you have any idea how such optimization should work? > > Regards, Peter > -- -- Howard. From howard.lovatt at gmail.com Mon Mar 29 18:43:46 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 30 Mar 2010 12:43:46 +1100 Subject: New In-Reply-To: References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <201003291256.12407.peter.levart@marand.si> Message-ID: <3dd3f56a1003291843v25bfe0c2tf60a2e853de9d4dc@mail.gmail.com> This is a two way argument, you could equally say can you demonstrate that the *compiler* can optimize my point 4 correctly. I am not suggesting that the JVM must optimize the creation away, just that it optionally can. If you are clear were the object is potentially created then the programmer can always do the optimization (just like the programmer already does for normal objects and is reminded to do so by the new keyword). On 29 March 2010 22:46, Osvaldo Doederlein wrote: > I have an idea to settle this debate and avoid further fight: a design that > depends on advanced optimization (either EA or some new one) should only be > considered as soon as we have, at least in alpha stage, said optimization in > the JDK7 project. And by "we have it" I imply that we also have specific > benchmarks that shows that the optimization does indeed eliminate the cost > it should. So, I'm not content with a microbenchmarks of non-lambda code > (e.g. en enhanced-for loop of collections that needs scalar replacement of > Iterator objects); I want to see benchmarks that show a well-representative > assorting of lambda code, demonstrating that the optimizer will typically > eliminate extra allocation imposed by the 'new'. > > [EA & stack allocation is already available; and we don't need a working > prototype of a compiler for the lambda proposal as it's possible to manually > write the same desugared code that would be emitted by such compiler. So, > whoever believes in the lemma "let's make a mess - the JIT will clean up > after us") must only write some benchmark code.] > > P.S.: EA & stack allocation are coming back in JDK 6u20, which is now in > beta and is planned to ship on June. It seems that EA is in enough good > shape as they're enabling it by default. OTOH, it's still exclusive to > HotSpot Server, and I have little hope that the Client compiler will get > this optimization any time soon. So I reinforce my negative vote (FWIW) on > any important language design that will be good only for server-side apps - > lambdas is a proposal for the next JavaSE platform, not for the next JavaEE > platform. > > A+ > Osvaldo > > 2010/3/29 Peter Levart > > On 03/29/10, Howard Lovatt wrote: >> > Just a note. I wouldn't suggest escape analysis as the appropriate >> > optimization. It would need to be a new optimization. >> > >> >> Do you have any idea how such optimization should work? >> >> Regards, Peter >> >> > -- -- Howard. From howard.lovatt at gmail.com Mon Mar 29 18:51:24 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 30 Mar 2010 12:51:24 +1100 Subject: New In-Reply-To: <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> Message-ID: <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> I think the strongest argument that anyone has made against using 'new' is your "economy of expression" argument, it then comes down to trading off conciseness against consistency and clarity. I go with consistency and clarity and you go with conciseness. I guess Alex or someone at Sun will decide :) With regard to caching lambdas I think the specification should make this optional, provided that it doesn't change program behavior. I.e. just like other optimizations in Java, e.g. in-lining a method until a new class is loaded that makes that in-lining invalid. On 30 March 2010 02:00, Joshua Bloch wrote: > Howard, > > On Mon, Mar 29, 2010 at 3:39 AM, Howard Lovatt > wrote: > > This group has also commented on the undesirability of Integer interning >> for > > some values and not others. > > > I don't think that's the problem so much as the fact that the spec mandates > which values must be interned. This causes people to write unreadable and > unmaintainable programs that take advantage of those guarantees. I with the > JLS had merely suggested that implementations might want to cache and reuse > common values as a quality-of-service issue. So I see this as a case of > overspecification, rather that an inherently bad idea. As I said a while > back, I believe the same behavior is appropriate for lambdas: the > specification should not mandate the creation of an object each time a > lambda expression is evaluate, and should note (using non-normative text), > that implementers should avoid creating such objects when it results in > improved performance. > > Regarding the desirability of using the "new" keyword for lambdas (a > purely syntactic decision): Even if each evaluation of a lambda expression > did result in the creation of a new object, a primary raison d'etre for > lambdas in Java is economy of expression. The "new" keyword (preceded and > followed by a space) is detrimental to that goal. > > Josh > > -- -- Howard. From howard.lovatt at gmail.com Mon Mar 29 19:02:40 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 30 Mar 2010 13:02:40 +1100 Subject: New In-Reply-To: <15e8b9d21003290914h75d37d60q2806bd11e3d1361d@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <15e8b9d21003290914h75d37d60q2806bd11e3d1361d@mail.gmail.com> Message-ID: <3dd3f56a1003291902g79b5b5cdlab5a05d89986a966@mail.gmail.com> In Java there are value semantics for primitives and reference semantics for Objects, I can't see how you can give lambdas value semantics and therefore I am proposing reference semantics. What you are proposing is some where in between the two, where it may be cached and effectively have value semantics or it may not, in which case you get reference semantics. In particular you are proposing that ==, !=, equals, and hashCode are effectively undefined for lambdas. I am far from convinced that this is a good idea, suppose I want a Set of lambdas! PS I didn't really get your comment about the GUI example. In particular the time of creation bit that you mentioned didn't seem relevant (other than to the particular GUI example). It was an example where object identity was important - i.e. like a Set as mentioned above. The purpose of the example was just to illustrate something that a Java programmer might reasonably expect to work and therefore should be supported (not that there aren't other ways of coding the problem). On 30 March 2010 03:14, Neal Gafter wrote: > On Mon, Mar 29, 2010 at 5:36 AM, Howard Lovatt wrote: > >> A number of people have commented about using new for lambdas, there are >> at >> least 4 good reasons to use new: >> >> 1. It is what the rest of Java uses, e.g.: >> >> List list = new ArrayList(); >> # lambda = new #(42); >> > > Only for object creation. A lambda expression is not a mechanism for > creating an object, so being consistent in this area would be a > disadvantage. > > >> 2. It is compatible with the diamond operator from Coin (assuming <> are >> used), e.g.: >> >> List list = new ArrayList<>(); >> # lambda = new #<>(42); >> > > Given that they have nothing whatsoever to do with each other, that's a > disadvantage too. > > >> 3. The main argument for not using new is that the compiler can 'lift' the >> lambda to be static if it doesn't access any instance fields or local >> variables. However this type of optimization has a poor history in >> Java,... >> > > This isn't an optimization. The compiler needs to translate each lambda > expression into a reference to a suitable object, and select an appropriate > lifetime for that object. The compiler should not intentionally generate > bad code in the hope that it will be improved later. > > ... Note how control over creation is critical, multiple frameClicked() >> calls >> >> can be safely eliminated but multiple fileMenuClicked() calls cannot >> because >> these toggle the menu. >> > > Actually, in your example control over creation (of the function object) is > not at all critical, because the creation time is not visible to the > program. I agree that multiple fileMenuClicked() calls cannot be > eliminated; that is because it has a side-effect "jobs.put(toggleFileMenu);" > having nothing at all to do with lambda creation. The (hidden) creation > time of the function object designated by the lambda has no impact on the > program's semantics. > -- -- Howard. From pbenedict at apache.org Mon Mar 29 21:11:16 2010 From: pbenedict at apache.org (Paul Benedict) Date: Mon, 29 Mar 2010 23:11:16 -0500 Subject: New In-Reply-To: <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> Message-ID: On Mon, Mar 29, 2010 at 8:51 PM, Howard Lovatt wrote: > I think the strongest argument that anyone has made against using 'new' is > your "economy of expression" argument, it then comes down to trading off > conciseness against consistency and clarity. I go with consistency and > clarity and you go with conciseness. I guess Alex or someone at Sun will > decide :) At one time, the "lambda" keyword was thrown around as an option. Any thoughts to floating that idea around again? I suppose it was supposed to function in the language like the "new" keyword: # foo = lambda #(42); Paul From int19h at gmail.com Mon Mar 29 21:29:42 2010 From: int19h at gmail.com (Pavel Minaev) Date: Mon, 29 Mar 2010 22:29:42 -0600 Subject: New In-Reply-To: References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> Message-ID: On Mon, Mar 29, 2010 at 10:11 PM, Paul Benedict wrote: > On Mon, Mar 29, 2010 at 8:51 PM, Howard Lovatt wrote: >> I think the strongest argument that anyone has made against using 'new' is >> your "economy of expression" argument, it then comes down to trading off >> conciseness against consistency and clarity. I go with consistency and >> clarity and you go with conciseness. I guess Alex or someone at Sun will >> decide :) > > At one time, the "lambda" keyword was thrown around as an option. Any > thoughts to floating that idea around again? I suppose it was supposed > to function in the language like the "new" keyword: > > # foo = lambda #(42); If you already have # there, then "lambda" serves no purpose whatsoever. # alone is enough to indicate the start of the lambda. If you don't use #, then you have to add it as a new reserved keyword - meaning that any existing Java code which uses "lambda" as identifier won't compile anymore. Nor can you make it an unambiguous context keyword, because, when generics are involved, you can get something like: lambda (C e)> (e + 1) which is a perfectly valid expression as far as they go: (((lambda < A) < B) > ((C < D) > e)) > (e + 1) Of course, it'll never type-check, but that doesn't stop it from being valid grammar for an expression, which is enough to confuse the parser. From howard.lovatt at gmail.com Mon Mar 29 21:36:22 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 30 Mar 2010 15:36:22 +1100 Subject: New In-Reply-To: References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> Message-ID: <3dd3f56a1003292136v54aca465u6425547ef15d230f@mail.gmail.com> You could introduce a class called Lambda (or Function) into java.lang then you could write: Lambda l = new Lambda<>(42); Something similar is proposed for MethodHandles by JSR 292. However I guess this discussion also falls under Alex's ruling that syntax discussions aren't to be considered. I am unclear as to whether semantic discussions are to be considered. On 30 March 2010 15:29, Pavel Minaev wrote: > On Mon, Mar 29, 2010 at 10:11 PM, Paul Benedict > wrote: > > On Mon, Mar 29, 2010 at 8:51 PM, Howard Lovatt > wrote: > >> I think the strongest argument that anyone has made against using 'new' > is > >> your "economy of expression" argument, it then comes down to trading off > >> conciseness against consistency and clarity. I go with consistency and > >> clarity and you go with conciseness. I guess Alex or someone at Sun will > >> decide :) > > > > At one time, the "lambda" keyword was thrown around as an option. Any > > thoughts to floating that idea around again? I suppose it was supposed > > to function in the language like the "new" keyword: > > > > # foo = lambda #(42); > > If you already have # there, then "lambda" serves no purpose > whatsoever. # alone is enough to indicate the start of the lambda. > > If you don't use #, then you have to add it as a new reserved keyword > - meaning that any existing Java code which uses "lambda" as > identifier won't compile anymore. Nor can you make it an unambiguous > context keyword, because, when generics are involved, you can get > something like: > > lambda (C e)> (e + 1) > > which is a perfectly valid expression as far as they go: > > (((lambda < A) < B) > ((C < D) > e)) > (e + 1) > > Of course, it'll never type-check, but that doesn't stop it from being > valid grammar for an expression, which is enough to confuse the > parser. > -- -- Howard. From opinali at gmail.com Tue Mar 30 06:09:18 2010 From: opinali at gmail.com (Osvaldo Doederlein) Date: Tue, 30 Mar 2010 10:09:18 -0300 Subject: New In-Reply-To: <3dd3f56a1003291843v25bfe0c2tf60a2e853de9d4dc@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <201003291256.12407.peter.levart@marand.si> <3dd3f56a1003291843v25bfe0c2tf60a2e853de9d4dc@mail.gmail.com> Message-ID: 2010/3/29 Howard Lovatt > This is a two way argument, you could equally say can you demonstrate that > the *compiler* can optimize my point 4 correctly. I am not suggesting that > the JVM must optimize the creation away, just that it optionally can. If you > are clear were the object is potentially created then the programmer can > always do the optimization (just like the programmer already does for normal > objects and is reminded to do so by the new keyword). > In practice, there is a strong direction of javac to not perform any optimizations at all (except IIRC, minimal dead-code removal based on constants so we have some level of conditional compilation). And my estimation of chances to change this direction are a rounding error above zero. Not to mention that relying on javac for advanced optimizations opens other can of worms if you consider the larger toolchain - e.g. the Eclipse Compiler project is still fixing Java5 bugs... A+ Osvaldo > On 29 March 2010 22:46, Osvaldo Doederlein wrote: > >> I have an idea to settle this debate and avoid further fight: a design >> that depends on advanced optimization (either EA or some new one) should >> only be considered as soon as we have, at least in alpha stage, said >> optimization in the JDK7 project. And by "we have it" I imply that we also >> have specific benchmarks that shows that the optimization does indeed >> eliminate the cost it should. So, I'm not content with a microbenchmarks of >> non-lambda code (e.g. en enhanced-for loop of collections that needs scalar >> replacement of Iterator objects); I want to see benchmarks that show a >> well-representative assorting of lambda code, demonstrating that the >> optimizer will typically eliminate extra allocation imposed by the 'new'. >> >> [EA & stack allocation is already available; and we don't need a working >> prototype of a compiler for the lambda proposal as it's possible to manually >> write the same desugared code that would be emitted by such compiler. So, >> whoever believes in the lemma "let's make a mess - the JIT will clean up >> after us") must only write some benchmark code.] >> >> P.S.: EA & stack allocation are coming back in JDK 6u20, which is now in >> beta and is planned to ship on June. It seems that EA is in enough good >> shape as they're enabling it by default. OTOH, it's still exclusive to >> HotSpot Server, and I have little hope that the Client compiler will get >> this optimization any time soon. So I reinforce my negative vote (FWIW) on >> any important language design that will be good only for server-side apps - >> lambdas is a proposal for the next JavaSE platform, not for the next JavaEE >> platform. >> >> A+ >> Osvaldo >> >> 2010/3/29 Peter Levart >> >> On 03/29/10, Howard Lovatt wrote: >>> > Just a note. I wouldn't suggest escape analysis as the appropriate >>> > optimization. It would need to be a new optimization. >>> > >>> >>> Do you have any idea how such optimization should work? >>> >>> Regards, Peter >>> >>> >> > > > -- > -- Howard. > From neal at gafter.com Tue Mar 30 09:30:55 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 30 Mar 2010 09:30:55 -0700 Subject: New In-Reply-To: <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB0788B.8090302@optrak.co.uk> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <17b2302a1003290800h5c21a2cu46744691eb8c4789@mail.gmail.com> <3dd3f56a1003291851h15eafc39mfe5adc7620227107@mail.gmail.com> Message-ID: <15e8b9d21003300930h20326453u317aba5580f6fc2@mail.gmail.com> On Mon, Mar 29, 2010 at 6:51 PM, Howard Lovatt wrote: > I think the strongest argument that anyone has made against using 'new' is > your "economy of expression" argument, it then comes down to trading off > conciseness against consistency and clarity. I go with consistency and > clarity and you go with conciseness. I guess Alex or someone at Sun will > decide :) > While I believe that a solution without "new" is more concise, I also believe it is more clear and consistent (because "The draft tries to take no position on when lambda expression evaluation physically occurs."). However, Alex's message of Mon, Mar 29, 2010 at 2:07 PM settled this issue ("The draft spec in the OpenJDK Lambda project will continue to avoid 'new' in the denotation of a lambda expression."), so we can take any further discussion off list. Cheers, Neal From mcnepp02 at googlemail.com Tue Mar 30 23:17:23 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Wed, 31 Mar 2010 06:17:23 +0000 Subject: New In-Reply-To: <3dd3f56a1003291843v25bfe0c2tf60a2e853de9d4dc@mail.gmail.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <201003291222.24898.peter.levart@marand.si> <3dd3f56a1003290339i49f1a173x90f67376501210d@mail.gmail.com> <201003291256.12407.peter.levart@marand.si> <3dd3f56a1003291843v25bfe0c2tf60a2e853de9d4dc@mail.gmail.com> Message-ID: On March 11th I've made a likewise remark: > Of course, if you intend to make lambda creation special with regards > to automatic instance caching by the compiler, using 'new' is not a > good idea. OTOH, is this really necessary? > I have confidence that the capable library developer will identify > stateless, non-capturing lambdas herself and provide factories for > them or store them in static fields. See the reply to my posting by Alex Blewitt from the same day: "This is essential, yes. The majority of 'capable library developers' may not, but the majority of Java developers using lambdas for the first time may well do so. You'd like the compiler to do that for you." 2010/3/30 Howard Lovatt : > This is a two way argument, you could equally say can you demonstrate that > the *compiler* can optimize my point 4 correctly. I am not suggesting that > the JVM must optimize the creation away, just that it optionally can. If you > are clear were the object is potentially created then the programmer can > always do the optimization (just like the programmer already does for normal > objects and is reminded to do so by the new keyword). From mcnepp02 at googlemail.com Tue Mar 30 23:28:33 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Wed, 31 Mar 2010 06:28:33 +0000 Subject: New In-Reply-To: <4BB11693.4090703@oracle.com> References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB11693.4090703@oracle.com> Message-ID: Hmm, stating that discussions on a public mailing list are "somewhat futile" is, with due respect, somewhat futile! Shall we cease to discuss the lambda proposal in its entirety, or just refrain from questioning certain aspects that you choose to decide on? BTW, it seems to me that many of those contributing to this discussion here can be considered "experts" on the topic. Thus, the prospective members of the "real" Expert Group would be well advised to consult this mailing list... 2010/3/29 Alex Buckley : > The draft spec in the OpenJDK Lambda project will continue to avoid > 'new' in the denotation of a lambda expression. > > Let me remind everyone that a spec from this project is likely to be > merely a starting point for a JSR Expert Group. The Expert Group members > may or may not review the mailing list archives of this project, so > endless syntax discussions here are somewhat futile. From alex.buckley at oracle.com Wed Mar 31 12:19:10 2010 From: alex.buckley at oracle.com (Alex Buckley) Date: Wed, 31 Mar 2010 12:19:10 -0700 Subject: New In-Reply-To: References: <3dd3f56a1003290236g4fedc95fpaf410c202cd47acd@mail.gmail.com> <4BB11693.4090703@oracle.com> Message-ID: <4BB3A02E.3020908@oracle.com> On 3/30/2010 11:28 PM, Gernot Neppert wrote: > Hmm, stating that discussions on a public mailing list are "somewhat > futile" is, with due respect, somewhat futile! What's futile is not the discussion per se, but the expectation doubtless held by some members of this mailing list that the discussion will be reviewed by EG members and affect their thinking. No-one can guarantee that EG members will do so. Some JCP members will not look at any OpenJDK project in any way under any circumstances. The draft Lambda spec will most likely be the sole starting point for EG discussions. Options explored on the Lambda list but not incorporated into the draft spec may have to be independently discovered by EG members. > Shall we cease to discuss the lambda proposal in its entirety, or just > refrain from questioning certain aspects that you choose to decide on? Anyone can discuss anything within the scope of the project defined at http://openjdk.java.net/projects/lambda/. By all means question any aspect of the draft Lambda spec. Just don't expect a guaranteed "Yes, you're right, it will definitely be done your way" response, because nothing is definite until the JSR goes final. > BTW, it seems to me that many of those contributing to this discussion > here can be considered "experts" on the topic. Thus, the prospective > members of the "real" Expert Group would be well advised to consult > this mailing list... Members of this mailing list are encouraged to join the JCP and, when the time comes, nominate themselves for EG membership for the Lambda JSR. That is the best way to ensure a thorough EG discussion. I for one would reproduce the content of the "Summary" mails for EG members. Alex From howard.lovatt at gmail.com Wed Mar 31 22:18:58 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 1 Apr 2010 16:18:58 +1100 Subject: New Message-ID: On Wed Mar 31 12:19:10 PDT 2010, Alex Buckley wrote: >On 3/30/2010 11:28 PM, Gernot Neppert wrote: >> Hmm, stating that discussions on a public mailing list are "somewhat >> futile" is, with due respect, somewhat futile! > >What's futile is not the discussion per se, but the expectation >doubtless held by some members of this mailing list that the discussion >will be reviewed by EG members and affect their thinking. No-one can >guarantee that EG members will do so. Some JCP members will not look at >any OpenJDK project in any way under any circumstances. The draft Lambda >spec will most likely be the sole starting point for EG discussions. >Options explored on the Lambda list but not incorporated into the draft >spec may have to be independently discovered by EG members. I would have thought that participation in a discussion group *like* this, or *other* contributions, would be *almost* a requirement for an EG member. After all, why should the other EG members have to educate someone who hasn't even availed themselves of readily available discussions. You can hardly claim to be an "expert" and yet "ignorant" of discussions about the topic at the same time :) [snip] ?-- Howard. PS I carefully said *almost* above since people outside mainstream Java might bring an interesting alternative perspective. However you would have thought such people would be the exception, not the rule.