From neal at gafter.com Mon May 10 09:27:19 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 10 May 2010 09:27:19 -0700 Subject: Close to 0.2 draft? Message-ID: Alex- It's been nearly three months since the 0.15 draft, and it is now less than two weeks before the TL (Tools and Languages) final integration preceding openjdk7 feature complete. If you've made progress on the specification and implementation, we would very much appreciate it being shared with us. If not, perhaps we can help. If Oracle has decided that this feature is no longer important for JDK7, that would be good to know too. Whatever is happening, silence sends the wrong message. -Neal From nathan.bryant at linkshare.com Mon May 10 10:03:51 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Tue, 11 May 2010 02:03:51 +0900 Subject: Close to 0.2 draft? References: Message-ID: <7FDA6630E1822F448C97A48D5D733094550A99@EXVMSTOR302.intra.rakuten.co.jp> One starts to wonder, why not just move to Scala -- there's much more that needs to be added to Java in order to build a coherent combination of features around lambdas. And now these delays, which affect not just users of ParallelArray but everyone who wants to build neatly refactored, testable software in Java. Seems like nobody's proposing to add declaration-site variance in Java => means FunctionN interfaces will not subtype the way they should. Nor is there specialization for primitives. (Scala's @specialized is broken for all but toy classes, but at least it's moving in the right direction) No JVM-level recognition that an object is a closure, and can hence be eliminated, as it can be with Scala's closure elimination (if the HOF can also be inlined.) The JVM seems to add something like an unavoidable machine word access to every polymorphic call site, even if they are supposedly inline-cached and not megamorphic, even inside a loop. Result that I've seen is approximately a 2x slowdown on toy microbenchmarks like "sum an array of integers" if implemented with any form of closures other than something that can be @inline'd in Scala. (And even in Scala, most HOF's are virtual hence can't be inlined.) I for one would like to see usable inlining in a language that /encourages/ the use of closures in every for loop. -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Neal Gafter Sent: Monday, May 10, 2010 12:27 PM To: Alexander Buckley; lambda-dev Subject: Close to 0.2 draft? Alex- It's been nearly three months since the 0.15 draft, and it is now less than two weeks before the TL (Tools and Languages) final integration preceding openjdk7 feature complete. If you've made progress on the specification and implementation, we would very much appreciate it being shared with us. If not, perhaps we can help. If Oracle has decided that this feature is no longer important for JDK7, that would be good to know too. Whatever is happening, silence sends the wrong message. -Neal From jkuhnert at gmail.com Tue May 11 11:39:59 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Tue, 11 May 2010 14:39:59 -0400 Subject: Close to 0.2 draft? In-Reply-To: References: Message-ID: Silence is probably the one thing that's always constant. Besides, probably have bigger concerns to think about - like how to expand on overcharging the DOD for bad software written by bad developers. What people don't know can't hurt them right? ;) On Mon, May 10, 2010 at 12:27 PM, Neal Gafter wrote: > Alex- > > It's been nearly three months since the 0.15 draft, and it is now less than > two weeks before the TL (Tools and Languages) final integration preceding > openjdk7 feature complete. ?If you've made progress on the specification and > implementation, we would very much appreciate it being shared with us. ?If > not, perhaps we can help. ?If Oracle has decided that this feature is no > longer important for JDK7, that would be good to know too. ?Whatever is > happening, silence sends the wrong message. > > -Neal > > From bobfoster at gmail.com Tue May 11 20:14:11 2010 From: bobfoster at gmail.com (Bob Foster) Date: Tue, 11 May 2010 20:14:11 -0700 Subject: Close to 0.2 draft? Message-ID: > Silence is probably the one thing that's always constant. Besides, > probably have bigger concerns to think about - like how to expand on > overcharging the DOD for bad software written by bad developers. What > people don't know can't hurt them right? ;) While snark is always appreciated, a little on-topic information would be good, too. Bob From brian.goetz at oracle.com Fri May 14 16:16:57 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 14 May 2010 19:16:57 -0400 Subject: Virtual extension methods -- a strawman design Message-ID: <4BEDD9E9.7050300@oracle.com> The attached document reflects our current thinking in the area of extension methods, which was introduced in section 8 of the Strawman proposal. This document (arguably) improves on the static extension method scheme presented there. Comments on the technical merits and flaws of the scheme are welcome (there are lots of details to be fleshed out, of course.) Comparisons to the previous (static) extension method scheme outlined in the strawman are also fair game. Comments to the effect of "I like XYZ other scheme better" are not. (Where XYZ could be use-site extension methods, traits, mixins, etc. Those have already been considered and rejected as viable approaches for Project Lambda.) From forax at univ-mlv.fr Fri May 14 17:14:40 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 02:14:40 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BEDE770.4090205@univ-mlv.fr> Le 15/05/2010 01:16, Brian Goetz a ?crit : > The attached document reflects our current thinking in the area of > extension methods, which was introduced in section 8 of the Strawman > proposal. This document (arguably) improves on the static extension > method scheme presented there. > > Comments on the technical merits and flaws of the scheme are welcome > (there are lots of details to be fleshed out, of course.) Comparisons > to the previous (static) extension method scheme outlined in the > strawman are also fair game. > > Comments to the effect of "I like XYZ other scheme better" are not. > (Where XYZ could be use-site extension methods, traits, mixins, etc. > Those have already been considered and rejected as viable approaches > for Project Lambda.) Hi Brian, It's good to know that your are working on lambdas. It seems that your attachment was crunched by the mailing list cerberus. R?mi From joe.darcy at oracle.com Fri May 14 17:13:56 2010 From: joe.darcy at oracle.com (Joe Darcy) Date: Fri, 14 May 2010 17:13:56 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDE770.4090205@univ-mlv.fr> References: <4BEDD9E9.7050300@oracle.com> <4BEDE770.4090205@univ-mlv.fr> Message-ID: <4BEDE744.4010506@oracle.com> R?mi Forax wrote: > Le 15/05/2010 01:16, Brian Goetz a ?crit : > >> The attached document reflects our current thinking in the area of >> extension methods, which was introduced in section 8 of the Strawman >> proposal. This document (arguably) improves on the static extension >> method scheme presented there. >> >> Comments on the technical merits and flaws of the scheme are welcome >> (there are lots of details to be fleshed out, of course.) Comparisons >> to the previous (static) extension method scheme outlined in the >> strawman are also fair game. >> >> Comments to the effect of "I like XYZ other scheme better" are not. >> (Where XYZ could be use-site extension methods, traits, mixins, etc. >> Those have already been considered and rejected as viable approaches >> for Project Lambda.) >> > > Hi Brian, > It's good to know that your are working on lambdas. > > It seems that your attachment was crunched by the mailing list cerberus. > > R?mi > > > I've posted Brian's document at http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf -Joe From neal at gafter.com Fri May 14 17:33:45 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 14 May 2010 17:33:45 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: Brian- There are two separable language proposals embedded here. The first is the ability to put default method implementations into an interface. The second is the ability to provide a method implementation by reference to another method. It isn't clear why one would intertwine the two proposals, and I don't understand the motivation for the latter (I don't buy the conclusion in the "Syntax Options" section). I'm guessing it is in part to simplify the implementation strategy, but that is a poor motivation. The proposed behavior for old class files might as well be done for all classes. That improves binary compatibility. Related to that, I'm concerned about your plan for handling ambiguities. I think there is a way that allows more interface evolutions without breaking existing code. The idea would be to have the VM always add the defender methods to classes missing them (i.e. javac would not do it), and have javac generate invokeinterface instructions for the invocations, rather than invokevirtual. Then the VM can match up the interface with its default implementation, even though there might be a defender method with the same signature in another interface. At compile-time, if there are two concrete methods in the candidate set (e.g. two defender methods), the invocation is ambiguous (i.e. it reduces to an existing language rule). My most important comment is this: the relationship between this proposal and the (not well described) goals of project lambda are not clear. What software engineering techniques are you trying to enable, and for whom, and how does this proposal improve things? Without a clear explanation, this is a solution in search of a problem. Cheers, Neal From brian.goetz at oracle.com Fri May 14 18:54:59 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 14 May 2010 21:54:59 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BEDFEF3.9090605@oracle.com> > There are two separable language proposals embedded here. The first is > the ability to put default method implementations into an interface. > The second is the ability to provide a method implementation by > reference to another method. It isn't clear why one would intertwine > the two proposals, and I don't understand the motivation for the latter > (I don't buy the conclusion in the "Syntax Options" section). I'm > guessing it is in part to simplify the implementation strategy, but that > is a poor motivation. The goal was not to provide "method implementation by reference", though that may be an unintended consequence. The intent was to move as little as possible from the spirit of interfaces while busting the choking restriction of "once you publish an interface, it is forever." > The proposed behavior for old class files might as well be done for all > classes. That improves binary compatibility. Probably so. The intent of compiler weaving (in addition to VM weaving) was to minimize the impact on the tools ecosystem (e.g., static code analyzers, IDEs, AOP tools, etc) in that classes implementing an extended interface that have been compiled with a current compiler will look to tools as complete implementations of the interface. Would be nice if this didn't create a huge ripple effect through the tools ecosystem; not only would that be mean to our friends, but it would delay adoption. > Related to that, I'm concerned about your plan for handling > ambiguities. I think there is a way that allows more interface > evolutions without breaking existing code. The idea would be to have > the VM always add the defender methods to classes missing them (i.e. > javac would not do it), and have javac generate invokeinterface > instructions for the invocations, rather than invokevirtual. Then the > VM can match up the interface with its default implementation, even > though there might be a defender method with the same signature in > another interface. At compile-time, if there are two concrete methods > in the candidate set (e.g. two defender methods), the invocation is > ambiguous (i.e. it reduces to an existing language rule). I will explore this as an option, it seems worth considering. > My most important comment is this: the relationship between this > proposal and the (not well described) goals of project lambda are not > clear. What software engineering techniques are you trying to enable, > and for whom, and how does this proposal improve things? Without a > clear explanation, this is a solution in search of a problem. Here's my rationale: adding closures to the language without closure-izing the libraries will be unsatisfying for the users. Without a means of interface evolution, we cannot closure-ize the libraries. We explored static extension methods, but they are pretty unsatisfying; it is impossible for an implementation to provide a better implementation. If its true that "today's problems come from yesterday's solutions", static extension methods feel to me like tomorrow's yesterday's problematic solution (parse that if you can!) From neal at gafter.com Fri May 14 22:22:53 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 14 May 2010 22:22:53 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDFEF3.9090605@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> Message-ID: On Fri, May 14, 2010 at 6:54 PM, Brian Goetz wrote: > > My most important comment is this: the relationship between this >> proposal and the (not well described) goals of project lambda are not >> clear. What software engineering techniques are you trying to enable, >> and for whom, and how does this proposal improve things? Without a >> clear explanation, this is a solution in search of a problem. >> > > Here's my rationale: adding closures to the language without closure-izing > the libraries will be unsatisfying for the users. Can you please unpack this assertion in more detail? Without a means of interface evolution, we cannot closure-ize the libraries. Ditto. We explored static extension methods, but they are pretty unsatisfying; it > is impossible for an implementation to provide a better implementation. Can you please give specific examples of the issues you anticipate with the specific closurizations you want to do in particular APIs? From scolebourne at joda.org Sat May 15 07:35:20 2010 From: scolebourne at joda.org (Stephen Colebourne) Date: Sat, 15 May 2010 15:35:20 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: On 15 May 2010 00:16, Brian Goetz wrote: > Comments to the effect of "I like XYZ other scheme better" are not. ?(Where > XYZ could be use-site extension methods, traits, mixins, etc. ?Those have > already been considered and rejected as viable approaches for Project > Lambda.) Sigh. I perfectly well understand that Oracle has met, discussed and decided to reject other options. The problem is that you've not done it /publicly/. As such, those of us outside Oracle are left with guessing at what thought processes you went through and reasoning you had. This makes it nigh on impossible to provide the meaningful feedback you'd like, or for you to win the trust of the broader community. Anyway... As it happens, I like the direction of the document. It enables class specific overrides of extension methods (which I consider essential) and manages the whole approach in an easy manner. It also solves my concern of a method not being in the immediate hierarchy of the object (and thus easily findable in the standard way). The approach does prevent users from adding there own methods to classes/interfaces, but I've always found that a little dubious. For that requirement, I'd prefer a different language change that made clear at the call-site that the methods are added by someone other than the API writer. I don't see a pressing need for that however, so the proposal covers the main use case. Personally, I would prefer to be able to write the implementation inline in the interface. Such an approach makes more sense that forcing the creation of public classes with random static methods. If the target is JDK7 then I agree with the idea of this being a compiler only approach. However, if this targets JDK8, then I would argue that a JVM based solution is probably more complete overall. ie. I believe that there is a timescale compromise here. Finally, I'd note that this language change affects design in JSR-310. Currently we choose an abstract class instead of an interface as its the only way to permit future evolution. If this change was going in, it might affect what the API. Stephen From pdoubleya at gmail.com Sat May 15 07:56:20 2010 From: pdoubleya at gmail.com (Patrick Wright) Date: Sat, 15 May 2010 16:56:20 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: Hi Brian I have comments on two sections: 4.3 Brittleness: offhand, it's difficult for me to say whether, if the selection of a default method for an interface changes between two releases, I would expect classes implementing the interface to dispatch to the new or the old method. My gut feeling is it would be less surprising if all classes I was loading and running used the new method, even if this introduced behavioral changes (hopefully none, or minor) into classes compiled against the original version of the interface. I could see this argued both ways, but I don't like the idea that two class files I was loading, both calling the same method via an interface, would end up executing two different methods at runtime for the same interface implementation. I would thus vote for a dynamic (so to speak) dispatch to the current method selected by the interface. I imagine when the tools developers catch up they could issue warnings about this happening by analyzing class files. Although in principle in the projects I work on I have the sources available to re-compile new JAR files, in practice what I see is that once a JAR file is blessed, and there is no compelling reason to rebuild it, that version of the JAR will be used going forward; this is especially noticeable in the open-source software we use--we use the end deliverable (JAR) and don't rebuild unless we have no other choice. That makes me think this "brittleness" issue will be something that we will have to keep in mind. 5 Implementation: I'm a little concerned about the cost of dynamically updating classes as they are loaded. Section 5.2 mentions doing this with classloaders--I assume you mean standard JDK classloaders, not a classloader implementation in the JVM itself? Class loading time is already blamed in some circles for (relatively) slow VM startup time; how can we avoid making this worse? I guess we won't know if this is an issue until you can experiment with a prototype implementation. Regards Patrick From jkuhnert at gmail.com Sat May 15 09:06:50 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Sat, 15 May 2010 12:06:50 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDFEF3.9090605@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> Message-ID: On Fri, May 14, 2010 at 9:54 PM, Brian Goetz wrote: > > Here's my rationale: adding closures to the language without closure-izing the > libraries will be unsatisfying for the users. Without a means of interface > evolution, we cannot closure-ize the libraries. We explored static extension > methods, but they are pretty unsatisfying; it is impossible for an > implementation to provide a better implementation. If its true that "today's > problems come from yesterday's solutions", static extension methods feel to me > like tomorrow's yesterday's problematic solution (parse that if you can!) > > > Could you not add closures first and save the library changes for a future update? The problem of retro-fitting the core API's does make sense in terms of time frame but it's kind of now or never (or a few years from now) in terms of having another opportunity to add them without another new major version number isn't it? It would be more ideal to have the libs retro-fitted but having the language feature would be even more important in my opinion..Users can find "satisifcation" in a future release while library designers / toolers / etc can quietly add support for it in anticipation of a future release update that expands and does the retro-fitting work.. maybe. From neal at gafter.com Sat May 15 09:16:13 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 15 May 2010 09:16:13 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: On Fri, May 14, 2010 at 4:16 PM, Brian Goetz wrote: > Comments to the effect of "I like XYZ other scheme better" are not. (Where > XYZ could be use-site extension methods, traits, mixins, etc. Those have > already been considered and rejected as viable approaches for Project > Lambda.) > This proposal is similar enough to some formulations of mixins/traits that it would be helpful to have a clear explanation of the relationship. What, precisely, are the differences between this proposal and "traditional" formulations of mixins/traits? Do you see this proposal as building on a record of success of language features already explored elsewhere, or do you see this as largely an innovation? From brian.goetz at oracle.com Sat May 15 09:22:30 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 12:22:30 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> Message-ID: <4BEECA46.2020806@oracle.com> > Could you not add closures first and save the library changes for a > future update? The problem of retro-fitting the core API's does make > sense in terms of time frame but it's kind of now or never (or a few > years from now) in terms of having another opportunity to add them > without another new major version number isn't it? Yes, and it is quite possible we may end up doing just that. To address the "another opportunity" point, note that the mechanism does (or should) allow for gradual evolution of interfaces (by dividing methods into "original" and "added later", but you get more than one chance to add later.) > It would be more ideal to have the libs retro-fitted but having the > language feature would be even more important in my opinion..Users can > find "satisifcation" in a future release while library designers / > toolers / etc can quietly add support for it in anticipation of a > future release update that expands and does the retro-fitting work.. > maybe. Quite so. But of course that depends on many things -- including the time lag between now and 7, and the time lag between 7 and 8. From forax at univ-mlv.fr Sat May 15 10:09:31 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 19:09:31 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BEED54B.7010400@univ-mlv.fr> Le 15/05/2010 16:35, Stephen Colebourne a ?crit : > On 15 May 2010 00:16, Brian Goetz wrote: > >> Comments to the effect of "I like XYZ other scheme better" are not. (Where >> XYZ could be use-site extension methods, traits, mixins, etc. Those have >> already been considered and rejected as viable approaches for Project >> Lambda.) >> > Sigh. > > I perfectly well understand that Oracle has met, discussed and decided > to reject other options. The problem is that you've not done it > /publicly/. As such, those of us outside Oracle are left with guessing > at what thought processes you went through and reasoning you had. This > makes it nigh on impossible to provide the meaningful feedback you'd > like, or for you to win the trust of the broader community. > > Anyway... > > As it happens, I like the direction of the document. It enables class > specific overrides of extension methods (which I consider essential) > and manages the whole approach in an easy manner. It also solves my > concern of a method not being in the immediate hierarchy of the object > (and thus easily findable in the standard way). > > The approach does prevent users from adding there own methods to > classes/interfaces, but I've always found that a little dubious. For > that requirement, I'd prefer a different language change that made > clear at the call-site that the methods are added by someone other > than the API writer. I don't see a pressing need for that however, so > the proposal covers the main use case. > > Personally, I would prefer to be able to write the implementation > inline in the interface. Such an approach makes more sense that > forcing the creation of public classes with random static methods. > > If the target is JDK7 then I agree with the idea of this being a > compiler only approach. However, if this targets JDK8, then I would > argue that a JVM based solution is probably more complete overall. ie. > I believe that there is a timescale compromise here. > A compiler only approach will not work because introducing a new method in an interface breaks the *binary* compatibility. like Neal, I am in favor of a VM only approach. > Finally, I'd note that this language change affects design in JSR-310. > Currently we choose an abstract class instead of an interface as its > the only way to permit future evolution. If this change was going in, > it might affect what the API. > > Stephen > R?mi From forax at univ-mlv.fr Sat May 15 10:09:40 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 19:09:40 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> Message-ID: <4BEED554.7070807@univ-mlv.fr> Le 15/05/2010 07:22, Neal Gafter a ?crit : [...] > We explored static extension methods, but they are pretty unsatisfying; it > >> is impossible for an implementation to provide a better implementation. >> > > Can you please give specific examples of the issues you anticipate with the > specific closurizations you want to do in particular APIs? > > I think I can :) Let say we want to add a method forEach in Collection: public interface Collection { ... public void forEach( void(T) lambda) default Collections.forEach(void(T)); } And in Collections: public static void forEach(Collection c, void(T) lambda) { for(T t: c) { lambda.invoke(t); } } So it will work with a TreeSet: TreeSet set = ... set.forEach((String s){ System.out.println(s); }); But because the default implementation use an Iterator, and maintaining a cursor on a tree cost more than traversing the tree recursively, the default impelemntation doesn't offer the best performance. What is cool with this proposal is that you can change the implementation of forEach for a TreeSet. public class TreeSet ... { public void forEach(void(T) lambda) { // faster implementation } } As far as I know, extension method of C# can't do that. R?mi From neal at gafter.com Sat May 15 10:04:54 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 15 May 2010 10:04:54 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEED554.7070807@univ-mlv.fr> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> Message-ID: On Sat, May 15, 2010 at 10:09 AM, R?mi Forax wrote: > > Can you please give specific examples of the issues you anticipate with > the > > specific closurizations you want to do in particular APIs? > > I think I can :) > Let say we want to add a method forEach in Collection: > R?mi- Are you asserting that Oracle wants to add the "forEach" method to Collection? (If not, then you haven't answered my question) -Neal From forax at univ-mlv.fr Sat May 15 10:23:23 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 19:23:23 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> Message-ID: <4BEED88B.3080700@univ-mlv.fr> Le 15/05/2010 19:04, Neal Gafter a ?crit : > On Sat, May 15, 2010 at 10:09 AM, R?mi Forax > wrote: > > > Can you please give specific examples of the issues you > anticipate with the > > specific closurizations you want to do in particular APIs? > > I think I can :) > Let say we want to add a method forEach in Collection: > > > R?mi- > > Are you asserting that Oracle wants to add the "forEach" method to > Collection? (If not, then you haven't answered my question) > > -Neal > forEach or map or filter are so common that I don't see why they will not be added to the JDK. R?mi From forax at univ-mlv.fr Sat May 15 10:41:01 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 19:41:01 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDFEF3.9090605@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> Message-ID: <4BEEDCAD.4040802@univ-mlv.fr> Le 15/05/2010 03:54, Brian Goetz a ?crit : [...] >> The proposed behavior for old class files might as well be done for all >> classes. That improves binary compatibility. >> > Probably so. The intent of compiler weaving (in addition to VM weaving) was > to minimize the impact on the tools ecosystem (e.g., static code analyzers, > IDEs, AOP tools, etc) in that classes implementing an extended interface that > have been compiled with a current compiler will look to tools as complete > implementations of the interface. Would be nice if this didn't create a huge > ripple effect through the tools ecosystem; not only would that be mean to our > friends, but it would delay adoption. > JSR 294 and JSR 292 already impact the format of the class file breaking the compatibility. The required changes are, in my opinion, more heavyweight than thoses proposed in this document. (The two specs add new constant items in the constant pool, and JSR292 adds a new opcode) So If extension method are added in jdk7, I don't buy this argument. R?mi From brian.goetz at oracle.com Sat May 15 10:34:22 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 13:34:22 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEED54B.7010400@univ-mlv.fr> References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> Message-ID: <4BEEDB1E.9030007@oracle.com> > A compiler only approach will not work because > introducing a new method in an interface breaks the *binary* > compatibility. > > like Neal, I am in favor of a VM only approach. As you correctly point out, the choices are VM-only and VM+compiler, and compiler-only is not an option. I see pros and cons for both options. The VM+compiler option is obviously more work for us, but seems likely to reduce the impact on the tools ecosystem. Ignoring the "which is more work" aspect, can you outline what you see as the advantages of the VM-only approach? From neal at gafter.com Sat May 15 10:48:58 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 15 May 2010 10:48:58 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEED88B.3080700@univ-mlv.fr> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> <4BEED88B.3080700@univ-mlv.fr> Message-ID: On Sat, May 15, 2010 at 10:23 AM, R?mi Forax wrote: > forEach or map or filter are so common that I don't see why > they will not be added to the JDK. > I can think of many reasons. Here's one: there is a major design decision about these kinds of methods that has been unexplored. That is: are high-order functions supplied with the JDK (such as map/filter) lazy or eager? This decision has an enormous impact on the shape of the ecosystem surrounding the APIs, and is not to be taken lightly. Making them different on related APIs (e.g. making them lazy on java.util.Iterable but eager on java.util.List) would be a likely disaster, but as far as I know there has been little if any consideration of the impact of this design fork. This decision also has a large impact on the possible evolution of these APIs and their use in concurrent contexts. From forax at univ-mlv.fr Sat May 15 11:07:33 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 20:07:33 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEEDB1E.9030007@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> <4BEEDB1E.9030007@oracle.com> Message-ID: <4BEEE2E5.6090403@univ-mlv.fr> Le 15/05/2010 19:34, Brian Goetz a ?crit : >> A compiler only approach will not work because >> introducing a new method in an interface breaks the *binary* >> compatibility. >> >> like Neal, I am in favor of a VM only approach. >> > As you correctly point out, the choices are VM-only and VM+compiler, and > compiler-only is not an option. I see pros and cons for both options. The > VM+compiler option is obviously more work for us, but seems likely to reduce > the impact on the tools ecosystem. Ignoring the "which is more work" aspect, > can you outline what you see as the advantages of the VM-only approach? > The principle reason: Java do the linking at runtime at least the linking of the method and not at compile time The practical reason: We have to do something at runtime, and doing it at compile time and runtime will weaken the implementation. Knowning that the tools that operate on bytecodes must be updated because other JSRs already require these tools to be updated, I don't see a reason to choose the VM+compiler option. R?mi From brian.goetz at oracle.com Sat May 15 11:01:29 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 14:01:29 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> <4BEED88B.3080700@univ-mlv.fr> Message-ID: <4BEEE179.2000601@oracle.com> >> forEach or map or filter are so common that I don't see why >> they will not be added to the JDK. > > I can think of many reasons. Here's one: there is a major design decision > about these kinds of methods that has been unexplored. One of the reasons it has been left unexplored is that it was not possible without breaking compatibility, so any such exploration would have been moot. And many of the mechanisms for allowing binary compatible interface evolution were unacceptable for various reasons. The technical points you raise are great discussions to have, and I welcome them. From abies at adres.pl Sat May 15 11:00:33 2010 From: abies at adres.pl (abies at adres.pl) Date: Sat, 15 May 2010 20:00:33 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: 4BEEDB1E.9030007@oracle.com Message-ID: "Brian Goetz" napisa?(a): > As you correctly point out, the choices are VM-only and VM+compiler, and > compiler-only is not an option. I see pros and cons for both options. The > VM+compiler option is obviously more work for us, but seems likely to reduce > the impact on the tools ecosystem. Ignoring the "which is more work" aspect, > can you outline what you see as the advantages of the VM-only approach? > Consistency - you will always get current target of default invoked, avoiding const-like inlining. As far as tools are concerned, some modification is anyway required to understand the extended interface format. Question is, does supporting two distinct versions of method 'guarding' is really helping to reduce the impact on tools? Will the compiler approach be enough for some tools to be compatible with really minimal changes? I'm bit scared that it will help in small way in short run, but require considerable more effort for tools like smart IDEs in longer run (where they will have to 'decode' compiler tricks to understand that in fact guard method is used). Regards, Artur Biesiadowski From neal at gafter.com Sat May 15 11:14:47 2010 From: neal at gafter.com (Neal Gafter) Date: Sat, 15 May 2010 11:14:47 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEEE179.2000601@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> <4BEED88B.3080700@univ-mlv.fr> <4BEEE179.2000601@oracle.com> Message-ID: On Sat, May 15, 2010 at 11:01 AM, Brian Goetz wrote: > >> forEach or map or filter are so common that I don't see why > >> they will not be added to the JDK. > > > > I can think of many reasons. Here's one: there is a major design > decision > > about these kinds of methods that has been unexplored. > > One of the reasons it has been left unexplored is that it was not possible > without breaking compatibility, so any such exploration would have been > moot. > And many of the mechanisms for allowing binary compatible interface > evolution were unacceptable for various reasons. > I'm troubled by the fact that a language proposal is being seriously considered without that exploration. > The technical points you raise are great discussions to have, and I welcome > them. > I expect that I will want to raise those points in response to the particular APIs that you suggest in response to my previous questions. Cheers, Neal From opinali at gmail.com Sat May 15 12:06:03 2010 From: opinali at gmail.com (Osvaldo Doederlein) Date: Sat, 15 May 2010 16:06:03 -0300 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEECA46.2020806@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEECA46.2020806@oracle.com> Message-ID: 2010/5/15 Brian Goetz > > Could you not add closures first and save the library changes for a > > future update? The problem of retro-fitting the core API's does make > > sense in terms of time frame but it's kind of now or never (or a few > > years from now) in terms of having another opportunity to add them > > without another new major version number isn't it? > > Yes, and it is quite possible we may end up doing just that. > I understand that the development of new APIs takes some time to design and implement, so leaving that for SE8 would be acceptable as a tradeoff for not missing lambdas at all or delaying SE7 further again. But I think at least the adaptation of existing APIs should be a no-brainer? Even if this amounts to only a handful of methods (like Collections.*), these are very critical APIs that tend to be used a lot because collections in general are pervasive in modern Java code. So we can allow application code to make a big step forward, even with a small and conservative first step of API retro-fitting. Like Mark said, "there's not a moment to lose" :) but I say that in the context of the Java language's window of opportunity to remain... well, attractive. Lambdas are already very late, even if JDK 7 ships tomorrow and with state of the art lambdas including full API support. Pushing a significant part of that to JDK 8 will be almost as bad as just skipping JDK 7 and having lambdas only in JDK 8 (or never at all). The Java platform blurs the line between the Java language and its core libs (in the sense that the language has no good extensibility mechanism and no built-in support for concepts that are handled at the language level in some other languages - so we rely a lot on core libs); so if SE7 only does the language part, this will create serious fragmentation when we have the library support later. We'd have two Java-with-lambdas variants, v7+ and v8+, and that will suck in the v7->v8 transition period. I can From dl at cs.oswego.edu Sat May 15 12:23:02 2010 From: dl at cs.oswego.edu (Doug Lea) Date: Sat, 15 May 2010 15:23:02 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEEDB1E.9030007@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> <4BEEDB1E.9030007@oracle.com> Message-ID: <4BEEF496.4050609@cs.oswego.edu> On 05/15/10 13:34, Brian Goetz wrote: >> A compiler only approach will not work because introducing a new method in >> an interface breaks the *binary* compatibility. >> >> like Neal, I am in favor of a VM only approach. > > As you correctly point out, the choices are VM-only and VM+compiler, and > compiler-only is not an option. I see pros and cons for both options. The > VM+compiler option is obviously more work for us, but seems likely to reduce > the impact on the tools ecosystem. Ignoring the "which is more work" > aspect, can you outline what you see as the advantages of the VM-only > approach? > Another choice is VM plus linking tools. If front-end compilers stay dumb and just put out the "obvious" code, it would be a good idea to offer developers a choice of whether they wanted fast vs dynamic via optional additional tools. With closures, it seems a sure thing that people will want to develop such tools anyway to get better performance for constructs that VMs don't always cope all that well with. As was pointed out last week by Nathan Bryant: > No JVM-level recognition that an object is a closure, and can hence be > eliminated, as it can be with Scala's closure elimination (if the HOF > can also be inlined.) The JVM seems to add something like an unavoidable > machine word access to every polymorphic call site, even if they are > supposedly inline-cached and not megamorphic, even inside a loop. Result > that I've seen is approximately a 2x slowdown on toy microbenchmarks > like "sum an array of integers" if implemented with any form of closures > other than something that can be @inline'd in Scala. (And even in Scala, > most HOF's are virtual hence can't be inlined.) I for one would like to > see usable inlining in a language that /encourages/ the use of closures > in every for loop. There is no need for front-end compilers to do this inlining etc either. It strikes me that jar-packaging tools might turn into optimizing linking tools to address a bunch of related performance problems at once. -Doug From brian.goetz at oracle.com Sat May 15 12:28:07 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 15:28:07 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEEF496.4050609@cs.oswego.edu> References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> <4BEEDB1E.9030007@oracle.com> <4BEEF496.4050609@cs.oswego.edu> Message-ID: <4BEEF5C7.5020600@oracle.com> > Another choice is VM plus linking tools. Quite so. Another possibility is to do the weaving at module installation time. From opinali at gmail.com Sat May 15 12:42:03 2010 From: opinali at gmail.com (Osvaldo Doederlein) Date: Sat, 15 May 2010 16:42:03 -0300 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEECA46.2020806@oracle.com> Message-ID: Oops, bad finger. Finishing last email: I can also wonder if javac could help in that transition, especially if we're not lucky wrt APIs. If I have code like myList.shuffle(), I suggest to consider the possibility of compiling this into a straight call to Collections.shuffle(List) (as defined by the 'default' in the defender). This might require some extra javac option, used together with -source 7 -target 6, or even with -target 7 if the API retrofitting comes only in SE8. The compiler could generate a warning if it can't see, from myList's static type, that the default implementation is guaranteed to be used even in the current platform. And when the compiler can see that, I suggest that the static call is always generated because that saves the cost (however small) of devirtualizing/inlining this call. Another suggestion: lift all Arrays.* methods into the primitive-array types, so we can write e.g. int[] arr = ...; arr.fill(10); This would make the defender methods proposal more orthogonal, even if (as usually) the mechanism is hardwired for the primitive array types - javac would just rewrite the code above to the proper invokestatic, without any intermediation or polymorphism. I know that half the people in this list will hate me for recalling that Java has these primitive arrays, but this is the language that we are evolving and there's no benefit in pretending that the old, ugly types don't exist or are not massively used even in new code. A+ Osvaldo 2010/5/15 Osvaldo Doederlein > 2010/5/15 Brian Goetz > > > Could you not add closures first and save the library changes for a >> > future update? The problem of retro-fitting the core API's does make >> > sense in terms of time frame but it's kind of now or never (or a few >> > years from now) in terms of having another opportunity to add them >> > without another new major version number isn't it? >> >> Yes, and it is quite possible we may end up doing just that. >> > > I understand that the development of new APIs takes some time to design and > implement, so leaving that for SE8 would be acceptable as a tradeoff for not > missing lambdas at all or delaying SE7 further again. But I think at least > the adaptation of existing APIs should be a no-brainer? Even if this amounts > to only a handful of methods (like Collections.*), these are very critical > APIs that tend to be used a lot because collections in general are pervasive > in modern Java code. So we can allow application code to make a big step > forward, even with a small and conservative first step of API retro-fitting. > > Like Mark said, "there's not a moment to lose" :) but I say that in the > context of the Java language's window of opportunity to remain... well, > attractive. Lambdas are already very late, even if JDK 7 ships tomorrow and > with state of the art lambdas including full API support. Pushing a > significant part of that to JDK 8 will be almost as bad as just skipping JDK > 7 and having lambdas only in JDK 8 (or never at all). The Java platform > blurs the line between the Java language and its core libs (in the sense > that the language has no good extensibility mechanism and no built-in > support for concepts that are handled at the language level in some other > languages - so we rely a lot on core libs); so if SE7 only does the language > part, this will create serious fragmentation when we have the library > support later. We'd have two Java-with-lambdas variants, v7+ and v8+, and > that will suck in the v7->v8 transition period. > > I can > > From forax at univ-mlv.fr Sat May 15 13:04:29 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 15 May 2010 22:04:29 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEEF496.4050609@cs.oswego.edu> References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> <4BEEDB1E.9030007@oracle.com> <4BEEF496.4050609@cs.oswego.edu> Message-ID: <4BEEFE4D.5080505@univ-mlv.fr> Le 15/05/2010 21:23, Doug Lea a ?crit : > On 05/15/10 13:34, Brian Goetz wrote: > >>> A compiler only approach will not work because introducing a new method in >>> an interface breaks the *binary* compatibility. >>> >>> like Neal, I am in favor of a VM only approach. >>> >> As you correctly point out, the choices are VM-only and VM+compiler, and >> compiler-only is not an option. I see pros and cons for both options. The >> VM+compiler option is obviously more work for us, but seems likely to reduce >> the impact on the tools ecosystem. Ignoring the "which is more work" >> aspect, can you outline what you see as the advantages of the VM-only >> approach? >> >> > Another choice is VM plus linking tools. > If front-end compilers stay dumb and just put out the "obvious" code, > it would be a good idea to offer developers a choice of > whether they wanted fast vs dynamic via optional additional tools. > With closures, it seems a sure thing that people will want to develop > such tools anyway to get better performance for constructs that > VMs don't always cope all that well with. As was pointed out last > week by Nathan Bryant: > [...] > There is no need for front-end compilers to do this inlining etc either. > It strikes me that jar-packaging tools might turn into optimizing > linking tools to address a bunch of related performance problems at > once. > > > -Doug > Premature optimization is the root of all evil :) The object that represents a closure already exists, it's java.dyn.MethodHandle. If the JIT is not able to optimize correctly a common use case the solution is to improve the JIT. R?mi From howard.lovatt at gmail.com Sat May 15 17:52:54 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sun, 16 May 2010 10:52:54 +1000 Subject: Compiler generated methods Message-ID: The proposal for extension methods is very close to my Trait proposal: http://www.artima.com/weblogs/viewpost.jsp?thread=220916 Including using a mixture of user, compiler, and VM generated methods. There is no controversy around allowing users to override the new methods in an interface; but there is a choice to made, is the compiler allowed to add methods? My proposal like the strawman allowed this, the reason I chose to do this was to reduce load time. The disadvantage is that if the interface is changed but the class that implements the interface isn't recompiled then the class will have the old implementation. This is probably not the ideal behavior, since it is most likely that the interface was upgraded to fix a bug. Balancing these competing requirements I decided previously that faster load time was the better trade off. This is a difficult choice; perhaps best to go with the majority vote! Subsequently to publishing my proposal 3 years ago I have changed my mind, I would now vote for VM (classloader) only since the compiler optimizations have a poor track record in Java (think String interning and static final in-lining). (Brian Goetz has also sighted simplifying tooling as a motivation for compiler generated methods, I don't see this since the tooling still has to cope with classloader generated methods.) -- Howard. From brian.goetz at oracle.com Sat May 15 18:10:48 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 21:10:48 -0400 Subject: Compiler generated methods In-Reply-To: References: Message-ID: <4BEF4618.8000908@oracle.com> > (Brian Goetz has also sighted simplifying tooling as a motivation for > compiler generated methods, I don't see this since the tooling still > has to cope with classloader generated methods.) The argument for the compiler+VM approach is a practical one aimed at risk mitigation, not elimination. With a VM-only approach, we are making a permanent change in a classfile invariant, which is likely to eventually require all tools to change. That has a real cost, and one which I will not impose lightly. By adding in compiler behavior, the only files that will be potentially confusing to tools will be pre-7.0 classfiles that implement extended interfaces and do not extend skeletal implementations (like AbstractSet) that provide implementations. And, in the event that this is a problem for tooling, and the tool vendor has not updated the tool (or the user has not paid for the upgrade), there's a workaround *that is under the control of the user, not the tool vendor*: recompile the class (or, equivalently, post-process the class with a weaving tool that will have the same effect). In no case are the users left high and dry with "old" tools. Over time, the set of old+moldy class files which meet the narrow criteria above will approach zero, at which point we re-enter the world where "old" tools just work without any workaround needed by the user. So it is quite possible that with a compiler+VM strategy, many third-party tools need not change at all. This is a tradeoff whereby we make some extra work for ourselves, but potentially alleviate pressure on the tools vendors. From howard.lovatt at gmail.com Sat May 15 19:06:38 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sun, 16 May 2010 12:06:38 +1000 Subject: Allow method bodies Message-ID: The proposal for extension methods allows for the extension method forwarding to a static method, e.g.: public interface List { boolean add(T t); // The rest of the existing List methods extension void sort() default Collections.sort; } A more flexible and more natural alternative is to allow a body definition: void sort() { Collections.sort( this ); } This is easy to implement also; you don't need a new class file format. You can translate this into: public interface List { boolean add(T t); // The rest of the existing Collection methods void sort(); public static final class $$Trait { public static void sort( final List self ) { Collections.sort( self ); } } } -- Howard. From howard.lovatt at gmail.com Sat May 15 19:25:26 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sun, 16 May 2010 12:25:26 +1000 Subject: Allow access to any super (diamond problem) Message-ID: In the proposed extension method strawman there is no way to access the super of an extension method. The classic example of this is the diamond problem (in the examples below I have assumed that method bodies are allowed - this is not part of the strawman): interface Base { String m() { return "Base"; } } interface Left extends Base { String m() { return "Left"; } } interface Right extends Base { String m() { return "Right"; } } interface Derived extends Left, Right {} An instance of Derived needs to specify what m does (since it is ambiguous), I suggest allowing a qualified super: Derived d = new Derived() { public String m() { return Base.super.m(); } }; The qualifying syntax is .super.. -- Howard. From brian.goetz at oracle.com Sat May 15 19:27:12 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 15 May 2010 22:27:12 -0400 Subject: Allow access to any super (diamond problem) In-Reply-To: References: Message-ID: <4BEF5800.4050500@oracle.com> I think you need to read the document more carefully. On 5/15/2010 10:25 PM, Howard Lovatt wrote: > In the proposed extension method strawman there is no way to access > the super of an extension method. The classic example of this is the > diamond problem (in the examples below I have assumed that method > bodies are allowed - this is not part of the strawman): > > interface Base { String m() { return "Base"; } } > interface Left extends Base { String m() { return "Left"; } } > interface Right extends Base { String m() { return "Right"; } } > interface Derived extends Left, Right {} > > An instance of Derived needs to specify what m does (since it is > ambiguous), I suggest allowing a qualified super: > > Derived d = new Derived() { public String m() { return Base.super.m(); } }; > > The qualifying syntax is.super. and arguments>. > > -- Howard. From howard.lovatt at gmail.com Sat May 15 19:32:14 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Sun, 16 May 2010 12:32:14 +1000 Subject: Allow access to any super (diamond problem) In-Reply-To: <4BEF5800.4050500@oracle.com> References: <4BEF5800.4050500@oracle.com> Message-ID: My apologies - I hadn't noticed section 4.1 On 16 May 2010 12:27, Brian Goetz wrote: > I think you need to read the document more carefully. > > On 5/15/2010 10:25 PM, Howard Lovatt wrote: >> >> In the proposed extension method strawman there is no way to access >> the super of an extension method. The classic example of this is the >> diamond problem (in the examples below I have assumed that method >> bodies are allowed - this is not part of the strawman): >> >> ? interface Base { String m() { return "Base"; } } >> ? interface Left extends Base { String m() { return "Left"; } } >> ? interface Right extends Base { String m() { return "Right"; } } >> ? interface Derived extends Left, Right {} >> >> An instance of Derived needs to specify what m does (since it is >> ambiguous), I suggest allowing a qualified super: >> >> ? Derived d = new Derived() { public String m() { return Base.super.m(); } >> }; >> >> The qualifying syntax is.super.> and arguments>. >> >> ? -- Howard. > -- -- Howard. From grev at miginfocom.com Sun May 16 00:17:40 2010 From: grev at miginfocom.com (Mikael Grev) Date: Sun, 16 May 2010 09:17:40 +0200 Subject: Compiler generated methods In-Reply-To: <4BEF4618.8000908@oracle.com> References: <4BEF4618.8000908@oracle.com> Message-ID: <5BFBA150-DD47-4310-A4DB-DE90AC0C516F@miginfocom.com> I think that tools not being updated is not the best reason for choosing one implementation over the other. By requiring updates you also introduce an advantage for updated tools. A tool that is actively updated should always have an advantage against one that isn't. By choosing a sub par approach just to deny competition is in my opinion thinking backwards. As long as the reason for changing something is sound one should do so. Otherwise the market grows stale and hinders innovation and progress. Cheers, Mikael On May 16, 2010, at 3:10 AM, Brian Goetz wrote: >> (Brian Goetz has also sighted simplifying tooling as a motivation for >> compiler generated methods, I don't see this since the tooling still >> has to cope with classloader generated methods.) > > The argument for the compiler+VM approach is a practical one aimed at risk > mitigation, not elimination. > > With a VM-only approach, we are making a permanent change in a classfile > invariant, which is likely to eventually require all tools to change. That > has a real cost, and one which I will not impose lightly. > > By adding in compiler behavior, the only files that will be potentially > confusing to tools will be pre-7.0 classfiles that implement extended > interfaces and do not extend skeletal implementations (like AbstractSet) that > provide implementations. And, in the event that this is a problem for > tooling, and the tool vendor has not updated the tool (or the user has not > paid for the upgrade), there's a workaround *that is under the control of the > user, not the tool vendor*: recompile the class (or, equivalently, > post-process the class with a weaving tool that will have the same effect). > In no case are the users left high and dry with "old" tools. > > Over time, the set of old+moldy class files which meet the narrow criteria > above will approach zero, at which point we re-enter the world where "old" > tools just work without any workaround needed by the user. So it is quite > possible that with a compiler+VM strategy, many third-party tools need not > change at all. This is a tradeoff whereby we make some extra work for > ourselves, but potentially alleviate pressure on the tools vendors. From neal at gafter.com Sun May 16 09:43:08 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 16 May 2010 09:43:08 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: Brian- Do you have a draft replacement for JLS3 8.4.8.4 http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.4(Inheriting Methods with Override-Equivalent Signatures)? -Neal From brian.goetz at Oracle.COM Sun May 16 10:15:09 2010 From: brian.goetz at Oracle.COM (Brian Goetz) Date: Sun, 16 May 2010 13:15:09 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BF0281D.3030801@oracle.com> Nope, it was a strawman design that I shared with the community to get feedback. Would you prefer that in future we refrain from posting anything until we have a full specification and reference implementation? On 5/16/2010 12:43 PM, Neal Gafter wrote: > Brian- > > Do you have a draft replacement for JLS3 8.4.8.4 > http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.4 > (Inheriting Methods with Override-Equivalent Signatures)? > > -Neal > From neal at gafter.com Sun May 16 11:54:46 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 16 May 2010 11:54:46 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BF0281D.3030801@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BF0281D.3030801@oracle.com> Message-ID: I'm not complaining, I'm just asking how that section will be handled. On Sun, May 16, 2010 at 10:15 AM, Brian Goetz wrote: > Nope, it was a strawman design that I shared with the community to get > feedback. Would you prefer that in future we refrain from posting anything > until we have a full specification and reference implementation? > > > On 5/16/2010 12:43 PM, Neal Gafter wrote: > >> Brian- >> >> Do you have a draft replacement for JLS3 8.4.8.4 >> http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.4 >> (Inheriting Methods with Override-Equivalent Signatures)? >> >> -Neal >> >> From howard.lovatt at gmail.com Sun May 16 17:16:23 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 17 May 2010 10:16:23 +1000 Subject: Virtual extension methods -- a strawman design Message-ID: When you post comments on a forum like lamda-dev it has a tendency to come over negative and critical. Particularly, if like me, you tend to get to the point. I could be wrong, but I get the impression that folks at Oracle are feeling that no one appreciates their work and it is just a never ending string of criticism aimed their way. Speaking for myself, I can say that my comments are not intended to be negative and I am glad that you are publicly discussing these issues and I am glad that more ambitious changes like lambdas and extension methods are on the agenda. From my point of view I will try and be more encouraging and not so terse (which as I said does come over negative). Hopefully this will encourage Oracle to make the process even more transparent. -- Howard. From mcnepp02 at googlemail.com Mon May 17 00:47:04 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Mon, 17 May 2010 08:47:04 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: I find the notion of "default implementations of interface methods" a little strange. Isn't that an oxymoron? In my understanding, an interface declares the set of methods that a are needed to implement the functionality that the interface was designed to provide. If any one method can be implemented by means of calling other interface methods, then it is strictly speaking not necessary at all. *) So, if one comes up with a new method for an existing interface, I see two possibilities: 1. The method can be expressed by invoking other methods. Then, why not simply do that? I can see nothing bad about "Collections.sort(List filter(boolean #condition(E)); This method cannot be implemented "externally" because of the necessity to create a collection of the same type. I see no reasonable way to provide a default implementation! *) And yes, I do think that java.util.Collection is already bloated. Methods such as "addAll" do not belong there! From howard.lovatt at gmail.com Mon May 17 01:05:50 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 17 May 2010 18:05:50 +1000 Subject: Virtual extension methods -- a strawman design Message-ID: Gernot, You are correct in saying that nothing can be added that can't already be done, i.e. you only gain convenience. To me though, writing: list.sort(); would be a welcome addition compared to: Collections.sort( list ); Like all features it is open to abuse, you can see that some API designers will add many convenience methods and the API will bloat. However, used well I think it will be a valuable addition and could hopefully replace abstract classes in many instances. Not so sure about your filter returning a new list of the same type example. You may well want to return a different data structure, perhaps one that shares the underlying elements so that you don't need to generate a new array (or some other underlying structure) or you generate the new array lazily. You can do what you want, same underlying structure, in Scala, but the mechanism is complicated and I am not sure worth the overhead of either the complicated typing that is necessary or the coding idiom that you use. -- Howard. From forax at univ-mlv.fr Mon May 17 01:28:24 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 17 May 2010 10:28:24 +0200 Subject: Extension method and covariant return type In-Reply-To: <4BEDD9E9.7050300@oracle.com> References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BF0FE28.5080205@univ-mlv.fr> I think there is something which is not specified: how covariant return type (and generics) interacts with the extension method. Suppose I have something like that: public interface Iterable { extension Iterable map(F(E) lambda) default Collections.iterableMap(F(E)); } public interface Collection implements Iterable { extension Collection map(F(E) lambda) default Collections.collectionMap(F(E)); } Currently when method that aren't defender method, the compiler adds a bridge (ACC_BRIDGE) method to all classes that implements the interfaces to do the bridge between the methods. Because defender methods can be inserted at runtime, the compiler can not add this bridge (the class can be compiler with a non 1.7 compiler). But the compiler can add another defender method that will do the bridge: public interface Collection implements Iterable { extension Collection map(F(E) lambda) default Collections.collectionMap(F(E)); extension Iterable map(F(E) lambda) default (Collection)Collection.map(F(E)); // brige inserted by the compiler } This means that the spec must be changed a little to allow to reference method that aren't static and with a slighty different signature (bridge can require to cast parameter). Note that because defender bridges are only added by the compiler, the Java spec can only authorize static default but the JVM spec must authorize reference to virtual method + casts (Hotspot already have call stubs to insert casts without requiring a full stack frame). A question remains, should declaration of extension method allowed in class (not only in interface) to retrofit standard bridge mecanism to always use defender bridge. R?mi From int19h at gmail.com Mon May 17 01:42:37 2010 From: int19h at gmail.com (Pavel Minaev) Date: Mon, 17 May 2010 01:42:37 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: On Mon, May 17, 2010 at 12:47 AM, Gernot Neppert wrote: > I find the notion of "default implementations of interface methods" a > little strange. > Isn't that an oxymoron? > > In my understanding, an interface declares the set of methods that a > are needed to implement the functionality that the interface was > designed to provide. If any one method can be implemented by means of > calling other interface methods, then it is strictly speaking not > necessary at all. *) > > So, if one comes up with a new method for an existing interface, I see > two possibilities: > > 1. The method can be expressed by invoking other methods. Then, why > not simply do that? I can see nothing bad about > "Collections.sort(List > 2. The method is "original" in its declared functionality. Thus, it > can not be expressed by invoking existing methods. Thus, how can you > provide a default implementation? > You miss a third case, which is a combination of the two above. Namely, the method can be expressed by invoking other methods in the most general case (that's our "default implementation"), but specific implementation of an interface may have a more efficient way of implementing this method. On one hand, you want simple implementations to be able to define the absolute minimum of methods. On the other, you want more advanced implementations to provide operations that are as efficient as possible, which, normally, means specialized implementations of them. Indeed, an existing example of an "interface" of this kind is abstract class java.io.InputStream - its only abstract method is a single-byte read(), and all other forms of read, such as e.g. read(byte[]), have default implementations defined in terms of that. Of course, in practice, any efficient implementation of InputStream would override read() and read(byte[]) separately, so as to optimize the latter. Note how InputStream has to be an abstract class today because of this, with all the restrictions and limitations it entails; while it could - arguably, more appropriately - be an interface with this proposal. Another example of this is Collection#size(). Technically, it could be defined on any Iterable, with the default implementation just iterating and counting elements until it reaches the end - this is a reasonable implementation for singly-linked lists or lazily generated sequences, for example. However, most actual collections, such as ArrayList, would rather override it to provide an efficient O(1) implementation. Indeed, this proposal would enable the addition of size() to Iterable in an entirely backwards-compatible way - all existing implementations of Collection would end up implementing Iterable#size(), and all Iterables which aren't Collections (and otherwise don't have size() defined on them) would gain the default implementation for size(), which, while not efficient, is guaranteed to behave correctly. Similar reasoning is applicable to Collection#contains, Collection#isEmpty, Collection#toArray, List#get, List#indexOf, List#lastIndexOf - and probably more. Consequently, I'd expect all those to be lifted up to Iterable in conjunction with this proposal, with default implementations provided there. From mcnepp02 at googlemail.com Mon May 17 02:45:00 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Mon, 17 May 2010 10:45:00 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: 2010/5/17 Pavel Minaev : > On Mon, May 17, 2010 at 12:47 AM, Gernot Neppert > wrote: >> > > Similar reasoning is applicable to Collection#contains, Collection#isEmpty, > Collection#toArray, List#get, List#indexOf, List#lastIndexOf - and probably > more. Consequently, I'd expect all those to be lifted up to Iterable in > conjunction with this proposal, with default implementations provided there. Hmm, I definitely hope this won't happen ;-) Iterable is quite useful as it is now. It's name conveys the purpose: provide an iterator that can be used to implement for-style loops. Why would you want to blur the distinction between Iterables and Collections? Actually, this makes me fear a new trend: Will people move as many methods as far 'upwards' as possible, providing more or less meaningful default implementations? From forax at univ-mlv.fr Mon May 17 03:09:21 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 17 May 2010 12:09:21 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BEDFEF3.9090605@oracle.com> <4BEED554.7070807@univ-mlv.fr> <4BEED88B.3080700@univ-mlv.fr> Message-ID: <4BF115D1.1030708@univ-mlv.fr> Le 15/05/2010 19:48, Neal Gafter a ?crit : > On Sat, May 15, 2010 at 10:23 AM, R?mi Forax > wrote: > > forEach or map or filter are so common that I don't see why > they will not be added to the JDK. > > > I can think of many reasons. Here's one: there is a major design > decision about these kinds of methods that has been unexplored. That > is: are high-order functions supplied with the JDK (such as > map/filter) lazy or eager? This decision has an enormous impact on > the shape of the ecosystem surrounding the APIs, and is not to be > taken lightly. Making them different on related APIs (e.g. making > them lazy on java.util.Iterable but eager on java.util.List) would be > a likely disaster, but as far as I know there has been little if any > consideration of the impact of this design fork. This decision also > has a large impact on the possible evolution of these APIs and their > use in concurrent contexts. In some use-cases, you want the lazy version and in some others you want the eager one, so I think there is no design decision because you have to provide both. I propose that by default: method on Collection and Map are eager. method on Iterator are lazy. and in java.util.Collections you have both versions: List lazyMap(List list, U(T) lambda) and List eagerMap(List list, U(T) lambda) R?mi From reinier at zwitserloot.com Mon May 17 04:07:17 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Mon, 17 May 2010 13:07:17 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: Many things would be gained, Gernot, and they come in two batches. The first batch is based on the notational difference between: Collections.sort(someList); and: someList.sort(); Advantage #1: someList.sort() is more consistent with java. When you want to do a verb to a noun you write noun.verb() in java, not RandomAndMostlyIrrelevantGroupingNoun.verb(noun);. In other words, it's prettier. There's an argument to be made that something like someList.set(idx, newVal); is an "intrinsic", "basic", "atomic", "core" (pick your preferred word :P) operation that cannot be expressed as a series of applications of other core/atomic/basic/instrinsic operations, whereas Collections.sort(list) is an extrinsic operation, and knowing the difference is nice. But this simply doesn't hold up, for two reasons: First of all, many existing extrinsic operations are defined in interfaces anyway. isEmpty() is extrinsic; it is almost always defined as size() != 0, and yet its in the interface. We can't very well REMOVE isEmpty() so this hypothetical land where intrinsic ops are of the noun.verb() variety and extrinsic ops are of the GroupingNoun.verb(noun) variety isn't true now and never will be true. Secondly, in many cases there's a set of operations which are mutually extrinsic, or where the line is blurry. For example, "List.set" can technically be considered extrinsic; after all, you could implement it with a combination of remove(int) and add(int, T). However, "set" works in the object returned by Arrays.asList, but remove and add don't, so how extrinsic is List.set? Why should we even ask developers to pick? Better to treat intrinsic/extrinsic as an ambiguous and mostly irrelevant detail that needn't be made so obvious. Advantage #2: In order to know what operations are possible on a given object, you check its methods. Whether you check the javadoc or just your IDE's auto-complete dialog, that's what you do. You cannot discover static helpers this way. Attempting to make your API easy to learn and work with is _far_ more difficult if that API includes a helper class with static methods, like Collections. Advantage #3 stems from Goetz's proposal's ability to let subtypes override implementations. For example, As Remi Forax has shown, the obvious implementation of a filter method, whether you use Collections.filter(list, filterFunction) or list.filterFunction(), is to iterate through it and call Iterator.remove() when the filter condition returns false. However, for certain collection implementations, there are more efficient ways to do it. If you write Collections.filter(list, filterFunction) then the static filter method in Collections must contain a bunch of "if list instanceof" statements to pick and choose an efficient implementation, and there's no way to define optimized or fixed behaviour in the subtype. But with the Goetz proposal you can write exceptional code in either location. --Reinier Zwitserloot On Mon, May 17, 2010 at 9:47 AM, Gernot Neppert wrote: > I find the notion of "default implementations of interface methods" a > little strange. > Isn't that an oxymoron? > > In my understanding, an interface declares the set of methods that a > are needed to implement the functionality that the interface was > designed to provide. If any one method can be implemented by means of > calling other interface methods, then it is strictly speaking not > necessary at all. *) > > So, if one comes up with a new method for an existing interface, I see > two possibilities: > > 1. The method can be expressed by invoking other methods. Then, why > not simply do that? I can see nothing bad about > "Collections.sort(List > 2. The method is "original" in its declared functionality. Thus, it > can not be expressed by invoking existing methods. Thus, how can you > provide a default implementation? > > > Here's this reasoning applied to an example that pops up frequently > when extension methods are mentioned: > A "filter" method on Collections. > > 1.hypothetical method declaration (modifying operation): > > /** > * Filters this collection. > * Removes all elements from this collection that do not satisfy the > condition. > * @return true if the collection changed due to the filtering. > */ > public boolean filter(boolean #condition(E)); > > This method can be easily implemented "externally", i.e. by means of > iterating over the collection and removing elements. > What would be gained by making this an interface method? > > 2.hypothetical method declaration (non-modifying operation): > > /** > * Returns the filtered content. > * Returns a collection of the same type as this collection that > contains only those elements > that satisfy the condition. > * @return the filtered collection. > */ > public Collection filter(boolean #condition(E)); > > This method cannot be implemented "externally" because of the > necessity to create a collection of the same type. > I see no reasonable way to provide a default implementation! > > > > > > > > > *) And yes, I do think that java.util.Collection is already bloated. > Methods such as "addAll" do not belong there! > > From mcnepp02 at googlemail.com Mon May 17 04:18:11 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Mon, 17 May 2010 12:18:11 +0100 Subject: Virtual extension methods -- inaccuracy in strawman proposal? Message-ID: Regarding Section 5 of the Strawman proposal: "However, the VM may wish to load class files compiled by older compilers, which under the current VM behavior would fail to load because they do not implement all the methods of the interface they claim to implement." This is not the case! *Classloading* does not fail if a class compiled against an older version of an interface does not implement all methods. Instead, trying to *invoke* such a method via the evolved interface fails at runtime with an AbstractMethodError. I think this is an important difference: If your statement were true, it would mean that the VM would already do the necessary checks during classloading. Modifying the VM so that it auto-generates the missing methods would not add huge additional overhead during classloading. As it stands, however, those checks would have to be added to the classloading sequence. In particular, the VM would have to check during classloading: - Is the class to be loaded (CTBL) abstract? - If not, check all interfaces implemented by CTBL for the presence of 'extension methods' - For every extension method, check whether the CTBL implements it, either directly or via its baseclasses. - For every non-implementd extension method, generate the code. Note that these checks cannot be skipped, even if it turns out that the CTBL does not need to be modified at all. From mcnepp02 at googlemail.com Mon May 17 04:43:51 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Mon, 17 May 2010 12:43:51 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: 2010/5/17 Reinier Zwitserloot : > Advantage #2: In order to know what operations are possible on a given > object, you check its methods. Whether you check the javadoc or just your > IDE's auto-complete dialog, that's what you do. You cannot discover static > helpers this way. Very good point: having the object declare its methods is definitely preferrable over having to find the right 'helper class'! Maybe I came around wrong: actually, I wasn't so much arguing against evolving interfaces. I was arguing against blurring the difference between interfaces and (abstract) classes by providing 'default implementations' Consider this hypothetical line of events for a moment: It is the year 2003. Sun is planning JDK 5. Due to many complaints of Java programmers, Sun decides that a 'sort' method was needed in java.util.List. They introduce a new interface List2 extends List { public void sort(Comparator comparator); } and have all JDK List-classes implement List2 instead of only List. They encourage the use of List2 in the API Doc. There would have been no compatibility issues at all. Programmers would have adopted List2 whenenver they were writing new code. Of course, if one goes down this line of thinking, one could additionally consider language support for versioning interfaces. Something like: public interface List.2 extends List { public void sort(Comparator comparator); } // Import with version number. Only one version can be imported: import java.util.List.2; // Use it simply by its base name 'List': List list = new ArrayList(); list.sort(String.CASE_INSENSITIVE_ORDER); // Or, used explicitly: java.util.List.2 list = new ArrayList(); list.sort(String.CASE_INSENSITIVE_ORDER); From brian.goetz at oracle.com Mon May 17 06:58:39 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 17 May 2010 09:58:39 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: <4BF14B8F.1090206@oracle.com> > It is the year 2003. Sun is planning JDK 5. Due to many complaints of > Java programmers, Sun decides that a 'sort' method was needed in > java.util.List. They introduce a new > > interface List2 extends List { > public void sort(Comparator comparator); > } > > and have all JDK List-classes implement List2 instead of only List. > They encourage the use of List2 in the API Doc. > > There would have been no compatibility issues at all. Programmers > would have adopted List2 whenenver they were writing new code. And in user code, people would have inserted casts to List2 whenever they encountered a List, sometimes with an instanceof check first, sometimes without. That would not be good for the readability or maintainability of Java code. From forax at univ-mlv.fr Mon May 17 07:14:06 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 17 May 2010 16:14:06 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BF14B8F.1090206@oracle.com> References: <4BEDD9E9.7050300@oracle.com> <4BF14B8F.1090206@oracle.com> Message-ID: <4BF14F2E.5010701@univ-mlv.fr> Le 17/05/2010 15:58, Brian Goetz a ?crit : >> It is the year 2003. Sun is planning JDK 5. Due to many complaints of >> Java programmers, Sun decides that a 'sort' method was needed in >> java.util.List. They introduce a new >> >> interface List2 extends List { >> public void sort(Comparator comparator); >> } >> >> and have all JDK List-classes implement List2 instead of only List. >> They encourage the use of List2 in the API Doc. >> >> There would have been no compatibility issues at all. Programmers >> would have adopted List2 whenenver they were writing new code. >> > And in user code, people would have inserted casts to List2 whenever they > encountered a List, sometimes with an instanceof check first, sometimes > without. That would not be good for the readability or maintainability of > Java code. > Eclipse developers do something similar. I was not happy when I tried to understand ITextViewer6: http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/text/ITextViewerExtension6.html I am not a big fan of having to understand all the history of an API before being able to use it. A friend of mine calls that: archeological programming. R?mi From nathan.bryant at linkshare.com Mon May 17 09:27:28 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Tue, 18 May 2010 01:27:28 +0900 Subject: Virtual extension methods -- a strawman design References: <4BEDD9E9.7050300@oracle.com> <4BEED54B.7010400@univ-mlv.fr> <4BEEDB1E.9030007@oracle.com><4BEEF496.4050609@cs.oswego.edu> <4BEEFE4D.5080505@univ-mlv.fr> Message-ID: <7FDA6630E1822F448C97A48D5D73309466DF96@EXVMSTOR302.intra.rakuten.co.jp> Remi wrote: >If the JIT is not able to optimize correctly a common use case >the solution is to improve the JIT. Sometimes compilers need hints. The fact that an object is an instance of a "closure class" (whatever that is) is one such (somewhat heuristic) hint. From int19h at gmail.com Mon May 17 09:29:12 2010 From: int19h at gmail.com (Pavel Minaev) Date: Mon, 17 May 2010 09:29:12 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: On Mon, May 17, 2010 at 2:45 AM, Gernot Neppert wrote: > 2010/5/17 Pavel Minaev :> On Mon, May 17, 2010 at 12:47 AM, Gernot Neppert > > wrote: > > > > Similar reasoning is applicable to Collection#contains, Collection#isEmpty, > > Collection#toArray, List#get, List#indexOf, List#lastIndexOf - and probably > > more. Consequently, I'd expect all those to be lifted up to Iterable in > > conjunction with this proposal, with default implementations provided there. > > Hmm, I definitely hope this won't happen ;-) > > Iterable is quite useful as it is now. It's name conveys the purpose: > provide an iterator that can be used to implement for-style loops. > ?Why would you want to blur the distinction between Iterables and Collections? It's not that I "want" to blur the distinction. The point is that the existing interface of Iterable already implies all those other operations - since they are all trivially implementable in terms of iterators - and you can have them today with static helpers. The only difference between having them as part of an interface or not is whether a particular implementation can elect to provide them in a more efficient way. If any Iterable can immediately support those operations, why _not_ have them in the interface? The old reasoning was that the burden on implementers would be too high. What else is there? > Actually, this makes me fear a new trend: Will people move as many > methods as far 'upwards' as possible, providing more or less > meaningful default implementations? I'd expect so. Why do you fear it? It means that many algorithms could be written in a more generic way than they are today. Where today you have to accept Collection, solely because you need size() on it, you'd be able to accept an Iterable instead, and be just as efficient as before when someone passes you a Collection. More genericity is good; why fear it? By the way, there's one other aspect of it. When you provide a default implementation, you are, effectively, codifying a formal "as-if" contract for a given method. I think that it is better than long-winded natural language descriptions. From brian.goetz at oracle.com Mon May 17 10:31:32 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 17 May 2010 13:31:32 -0400 Subject: First draft of translation document Message-ID: <4BF17D74.6090104@oracle.com> We've posted a document describing a (somewhat naive) translation strategy for translation of lambda expressions by javac here: http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf From neal at gafter.com Mon May 17 12:53:12 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 17 May 2010 12:53:12 -0700 Subject: First draft of translation document In-Reply-To: <4BF17D74.6090104@oracle.com> References: <4BF17D74.6090104@oracle.com> Message-ID: Brian- The latest "official" jsr292 draft (May 2008) doesn't contain any special treatment for the ldc instruction. I suspect there are other jsr292 features referenced here not in that draft. Where should I find a draft of jsr292 that corresponds to the assumptions in this document? Cheers, Neal On Mon, May 17, 2010 at 10:31 AM, Brian Goetz wrote: > We've posted a document describing a (somewhat naive) translation strategy for > translation of lambda expressions by javac here: > > ? http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > > > From brian.goetz at oracle.com Mon May 17 14:28:16 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 17 May 2010 17:28:16 -0400 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> Message-ID: <4BF1B4F0.6050500@oracle.com> This is quite common when activities evolve in parallel -- one must make assumptions (or wishful thinking) about the future course of other coincident activities. As to the specific issue of LDC support for method handle literals, John Rose mentioned it on his blog some time ago [1,2] and provided an implementation to the OpenJDK MLVM project in March 2010. The 292 EG still has yet to hash out the details; in the event this is not ultimately surfaced in 292 we will then have to construct an alternate strategy. [1] http://blogs.sun.com/jrose/entry/view_from_the_summit [2] http://blogs.sun.com/jrose/entry/anatomy_of_a_call_site On 5/17/2010 3:53 PM, Neal Gafter wrote: > Brian- > > The latest "official" jsr292 draft (May 2008) doesn't contain any > special treatment for the ldc instruction. I suspect there are other > jsr292 features referenced here not in that draft. Where should I > find a draft of jsr292 that corresponds to the assumptions in this > document? > > Cheers, > Neal > > On Mon, May 17, 2010 at 10:31 AM, Brian Goetz wrote: >> We've posted a document describing a (somewhat naive) translation strategy for >> translation of lambda expressions by javac here: >> >> http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf >> >> >> From reinier at zwitserloot.com Mon May 17 16:25:10 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 18 May 2010 01:25:10 +0200 Subject: First draft of translation document In-Reply-To: <4BF1B4F0.6050500@oracle.com> References: <4BF17D74.6090104@oracle.com> <4BF1B4F0.6050500@oracle.com> Message-ID: I defer judgement on performance to your capable hands, but I did note some apparent mistakes in the example code listed in section 6.2: - The closure$1 method is static yet seems to be trying to access the "bottom" and "top" fields of the B2.Closure$1 class. - B2.Closure$1 implements Filter but presuming closure$1 was not meant to be static, unless "closure$1" is the actual name of the one method in the Filter SAM, "closure$1" is the wrong name. Presumably it should be called "filter" or some such. - Filter's signature is Filter, and its one method takes a T. that method's erased signature would be (Ljava/lang/Object;)Z, and that's what list.filter() will be working with, not (LPerson;)Z. Javac's standard strategy here is to make filter(Person) the 'true' method and generate a bridge method with signature filter(Object) which simply wraps a call on to the true filter(Person), along with a cast. Given that the most likely place that closure object will end up will use only the bridge method, this seems needlessly inefficient. Is it perhaps possible to generate only the filter(Object) variant? --Reinier Zwitserloot On Mon, May 17, 2010 at 11:28 PM, Brian Goetz wrote: > This is quite common when activities evolve in parallel -- one must make > assumptions (or wishful thinking) about the future course of other > coincident > activities. > > As to the specific issue of LDC support for method handle literals, John > Rose > mentioned it on his blog some time ago [1,2] and provided an implementation > to > the OpenJDK MLVM project in March 2010. The 292 EG still has yet to hash > out > the details; in the event this is not ultimately surfaced in 292 we will > then > have to construct an alternate strategy. > > [1] http://blogs.sun.com/jrose/entry/view_from_the_summit > [2] http://blogs.sun.com/jrose/entry/anatomy_of_a_call_site > > On 5/17/2010 3:53 PM, Neal Gafter wrote: > > Brian- > > > > The latest "official" jsr292 draft (May 2008) doesn't contain any > > special treatment for the ldc instruction. I suspect there are other > > jsr292 features referenced here not in that draft. Where should I > > find a draft of jsr292 that corresponds to the assumptions in this > > document? > > > > Cheers, > > Neal > > > > On Mon, May 17, 2010 at 10:31 AM, Brian Goetz > wrote: > >> We've posted a document describing a (somewhat naive) translation > strategy for > >> translation of lambda expressions by javac here: > >> > >> http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > >> > >> > >> > > From mcnepp02 at googlemail.com Tue May 18 00:01:48 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Tue, 18 May 2010 08:01:48 +0100 Subject: First draft of translation document In-Reply-To: <4BF17D74.6090104@oracle.com> References: <4BF17D74.6090104@oracle.com> Message-ID: Interesting to see the various possibilities of converting lambda expressions into callable Java objects! I wonder why the approach from paragraph 6.2 (Translation as inner class) is not also viable for paragrah 5 (stateless functions). Paragrah 5 relies on the assumption: "Additionally, we assume that the MethodHandle class will be extended to provide a method asSam(Class sam) which will provide an optimized form of injecting a SAM interface into a method handle." At the end of the day, doesn't that mean that an anonymous proxy class will be created anyway? In what respect will your approach be superiour to simply generating code for a static inner class, such as: private static Block $sam$1= new Block() { public void invoke(String s){ System.out.println(s); } }; From peter.levart at marand.si Tue May 18 00:05:44 2010 From: peter.levart at marand.si (Peter Levart) Date: Tue, 18 May 2010 09:05:44 +0200 Subject: First draft of translation document In-Reply-To: <4BF17D74.6090104@oracle.com> References: <4BF17D74.6090104@oracle.com> Message-ID: <201005180905.44889.peter.levart@marand.si> Hello Brian, Good work. Just a note on section "10. Multiple lambdas per scope". While this approach is logically correct and optimizes the number of Objects created/classes used, it has a drawback that it might introduce memory leaks. A long-lived lambda might hold on to the references that it didn't actually capture in the source code. To remedy this, the set of mutable variables S captured in the same scope by multiple lambdas where each lambda (Li; i=1..n) captures it's own subset (Si; i=1..n) would in general have to be broken into at most 2^n-1 disjunctive non-empty subsets (much less in common cases) and a separate frame object created for each of them. Regards, Peter On 05/17/10, Brian Goetz wrote: > We've posted a document describing a (somewhat naive) translation strategy for > translation of lambda expressions by javac here: > > http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > > > From Kieron.Wilkinson at paretopartners.com Tue May 18 00:36:26 2010 From: Kieron.Wilkinson at paretopartners.com (Kieron.Wilkinson at paretopartners.com) Date: Tue, 18 May 2010 08:36:26 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> Message-ID: On 17 May 2010, Pavel Minaev wrote: > I'd expect so. Why do you fear it? It means that many algorithms could > be written in a more generic way than they are today. Where today you > have to accept Collection, solely because you need size() on it, you'd > be able to accept an Iterable instead, and be just as efficient as > before when someone passes you a Collection. More genericity is good; > why fear it? >From my perspective, it rather depends on whether the type indicates a contract. Collection implies a finite number of items, but Iterable does not. For many purposes, calling something like size() on an Iterable object will never return. If the method is not there, you can't call it. For example, you might have a Iterable implementation that provides an infinite set of calculated items, like the Fibonacci sequence. This sort of thing can be quite common (and very useful) when programming in a more functional style. Kieron This message may contain confidential and privileged information and is intended solely for the use of the named addressee. Access, copying or re-use of the e-mail or any information contained therein by any other person is not authorised. If you are not the intended recipient please notify us immediately by returning the e-mail to the originator and then immediately delete this message. Although we attempt to sweep e-mail and attachments for viruses, we do not guarantee that either are virus-free and accept no liability for any damage sustained as a result of viruses. Please refer to http://www.bnymellon.com/disclaimer/piml.html for certain disclosures. From forax at univ-mlv.fr Tue May 18 01:11:57 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Tue, 18 May 2010 10:11:57 +0200 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> Message-ID: <4BF24BCD.9010008@univ-mlv.fr> Le 18/05/2010 09:01, Gernot Neppert a ?crit : > Interesting to see the various possibilities of converting lambda > expressions into callable Java objects! > > I wonder why the approach from paragraph 6.2 (Translation as inner > class) is not also viable for paragrah 5 (stateless functions). > Paragrah 5 relies on the assumption: > > "Additionally, we assume that the MethodHandle class will be extended > to provide a method asSam(Class sam) which will provide an optimized > form of injecting a SAM interface into a method handle." > > At the end of the day, doesn't that mean that an anonymous proxy class > will be created anyway? > No, not necessarily. That's why asSam() is cool. The idea behind is to optimize the class that have only one abstract method to store that method in a special place and to have a specific path in the VM to deal with these new kind of objects. In that case method handles and SAM objects can share the same representation in the VM (or a similar one) thus the VM will be able to create a new inner class from a method handle without creating a new class. > In what respect will your approach be superiour to simply generating > code for a static inner class, such as: > > private static Block $sam$1= new Block() { > public void invoke(String s){ > System.out.println(s); > } > }; > > R?mi From mcnepp02 at googlemail.com Tue May 18 01:27:53 2010 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Tue, 18 May 2010 09:27:53 +0100 Subject: First draft of translation document In-Reply-To: <4BF24BCD.9010008@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF24BCD.9010008@univ-mlv.fr> Message-ID: I see. So all invocations of 'asSam' for the same SAM-type will yield instances of the same (anonymous) proxy class - quite cool ;-) Thanks for the explanation! 2010/5/18 R?mi Forax : > Le 18/05/2010 09:01, Gernot Neppert a ?crit : > No, not necessarily. That's why asSam() is cool. > > The idea behind is to optimize the class that have only > one abstract method to store that method > in a special place and to have a specific path > in the VM to deal with these new kind of objects. > > In that case method handles and SAM objects > can share the same representation in the VM > (or a similar one) thus the VM will be able > to create a new inner class from a method handle > without creating a new class. > From howard.lovatt at gmail.com Tue May 18 01:43:41 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 18 May 2010 18:43:41 +1000 Subject: First draft of translation document Message-ID: It is good to see a draft of how lambdas might be implemented, I think that it makes it easier to discuss some issues and also clarifies some parts of the specification. An alternative to using MethodHandles is to use a Callable interface and then use inner classes to capture the 'frame'; see runnable code below. I suspect that the Callable implementation will be: 1. Faster execution in most cases: avoids boxing, binding of arguments, and interface injection. 2. Simpler: always the same pattern of transformation, no need to bind arguments, and no need to inject interfaces. Like any system that doesn't reify the types, including using MethodHandles, the code below has the normal erasure problems of: can't have two methods with the same erased signature, can't create an array, boxing of array elements, no generic static fields, etc. However in both the code below, see Callable2VL, and in the proposed MethodHandle translation there is partial reification (for primitive types and for SAM types), this may well eliminate the boxing of array elements problem. In the above comments I said "faster execution in most cases", this need to be qualified on two fronts: A. It is hard to be certain, since optimizing JVMs with MethodHandles aren't available. B. A case where the alternate translation might well be slower, is if no variables are captured and no interfaces are injected. Expanding point B further; the Callable implementation loads one class per lambda and creates one object per lambda, whereas the MethodHandle implementation creates multiple objects per lambda (one for the lambda, others for the capture, others for the binding, and others for the interface injection) but can avoid a class load if there is no interface injection (it may also be able to inject interfaces more efficiently than you can load classes and the number of extra objects created may be able to be minimized). As I said; good to see some implementation ideas, -- Howard. ================================================================================= /* * This file is part of Howard Lovatt's PhD Thesis: * "A Pattern Enforcing Compiler (PEC) for Java". * Copyright (C) 2003-2010 Howard Lovatt * PEC is trademarked by Howard Lovatt and Java is trademarked by Sun Microsystems * More info: pec.dev.java.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * You can contact Howard Lovatt at howard.lovatt at iee.org * or at 12 Roseberry St., Balmain, NSW, Australia, 2041. */ package erasedlambdas; /** * Exmples of lambda translation using Callable instead of MethodHandle. It is * an alternative to {@link * http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf}. Notes: * *
    *
  1. Main examples shown below only use generic parameters, however * technique can be extended to use primitives by defining version of * Callable for boolean, double, long, and void (an example primitive * Callable is given along with some niotes below - see Callable2VL). Also * see section 8 of referenced PDF.
  2. *
  3. Examples only show up to two arguments, suggest a logirithmic scale be * used in practice and arguments 0, 1, 2, 5, 10, and 20 supported. Above 20 * is an error (Scala goes to 22 in steps of 1 but does not support * primitives). Also see section 8 of referenced PDF.
  4. *
  5. Like the referenced PDF, any single abstract method (SAM) types must be * an interface (this restrictiuon could be lifted).
  6. *
  7. Like the referenced PDF, has the normal erasure problems of can't have * two methods with the same erased signature, can't create an array, etc.
  8. *
  9. The examples use _ in names instead of $ so that they will compile
  10. *
  11. The concept is to always use an inner class, similar to referenced PDF * section 6.2, that captures variables and is the lambda that is passed * round. These inner classes are termed frames.
  12. *
  13. If no access to the classes fields are required then the inner class, * frame, is static.
  14. *
  15. If there is a nested scope then there are nested frames.
  16. *
  17. If a variable is required in two frames then it is captured in the * first frame and the first frame is captured in the second frame.
  18. *
  19. Instead of a MethodHandle a Callable interface is used
  20. *
  21. The advantage are: * *
      *
    1. Faster execution in most cases: avoids boxing, binding of * arguments, and interface injection.
    2. *
    3. Simpler: always the same patern of transformation, no need to bind * arguments, and no need to inject interfaces.
    4. *
    *
  22. *
* * @author Howard Lovatt * @version 1 (2010-05-18) */ public class Main { public static void main( final String[] notUsed ) { new A().foo(); new B().foo(); new C().foo(); new D().foo(); } } // Examples /** *
class A {
  public void foo() {
    List<String> list = ...
    list.forEach( #(String s) { System.out.println(s); } );
  }
}
 * 
*/ class A { private static final Block frame_1 = new Frame_1(); // Lifted to outer scope public void foo() { List list = new List( String.class, "A", "B", "C" ); list.forEach( frame_1 ); } private static class Frame_1 // No need to extend a FrameN class implements Callable1, Block { public Void _call( String a1 ) { call( a1 ); return null; } public void call( String s ) { System.out.println( s ); } } } /** *
class B {
  public void foo() {
    List>Person< list = ...
    final int bottom = ..., top = ...;
    List inRange = list.filter(
        #(Person p) { p.size >= bottom && p.size <= top } );
    System.out.println( inRange );
  }
}
 * 
*/ class B { public void foo() { List list = new List( Person.class, new Person(), new Person(), new Person() ); final int bottom = 1; final int top = 1; final Frame_1 frame_1 = new Frame_1( bottom, top ); List inRange = list.filter( frame_1 ); System.out.println( inRange ); } private static class Frame_1 extends Frame2 implements Callable1, Filter { Frame_1( final Integer e1, final Integer e2 ) { super( e1, e2 ); } public Boolean _call( Person a1 ) { return filter( a1 ); } public boolean filter( Person p ) { return ( p.size >= _e1 ) && ( p.size <= _e2 ); } } } /** *
class C {
  public void foo() {
      List<String> list = ...
      shared int totalSize = 0;
      list.forEach( #(String s) { totalSize += s.length() } );
      System.out.println(totalSize);
  }
}
 * 
*/ class C { public void foo() { List list = new List( String.class, "a", "aa", "aaa" ); final Frame_1 frame_1 = new Frame_1( 0 ); list.forEach( frame_1 ); System.out.println( frame_1._e1 ); } private static class Frame_1 extends Frame1 implements Callable1, Block { Frame_1( final Integer e1 ) { super( e1 ); } public Void _call( String a1 ) { call( a1 ); return null; } public void call( String s ) { _e1 += s.length(); } } } /** *
class D {
    public void foo() {
        shared int grandTotal = 0;
        List<Department> departments = ...
        List<Employee> employees = ...
        departments.forEach( #(Department d) {
            shared int deptTotal = 0;
            employees
                .filter(#(Employee e) { e.dept == d })
                .forEach(#(Employee e) {
                    deptTotal += e.salary;
                    grandTotal += e.salary;
            });
            System.out.printf("Total for dept %s = %d\n",
                              d, deptTotal);
        });
        System.out.printf("Grand total = %d\n", grandTotal);
    }
}
 * 
*/ class D { public void foo() { List departments = new List( Department.class, new Department(), new Department() ); final List employees = new List( Employee.class, new Employee( departments.get( 0 ), 100 ), new Employee( departments.get( 1 ), 10 ), new Employee( departments.get( 1 ), 20 ) ); final Frame_1 frame_1 = new Frame_1( 0, employees ); departments.forEach( frame_1 ); System.out.printf( "Grand total = %d\n", frame_1._e1 ); } private static class Frame_1 extends Frame2> implements Callable1, Block { Frame_1( final Integer e1, final List e2 ) { super( e1, e2 ); } public Void _call( Department a1 ) { call( a1 ); return null; } public void call( Department d ) { final Frame_2 frame_2 = new Frame_2( d ); final Frame_3 frame_3 = new Frame_3( 0 ); _e2.filter( frame_2 ).forEach( frame_3 ); System.out.printf( "Total for dept %s = %d\n", d, frame_3._e1 ); } private static class Frame_2 extends Frame1 implements Callable1, Filter { Frame_2( final Department e1 ) { super( e1 ); } public Boolean _call( Employee a1 ) { return filter( a1 ); } public boolean filter( Employee e ) { return e.dept == _e1; } } private class Frame_3 extends Frame1 implements Callable1, Block { Frame_3( final Integer e1 ) { super( e1 ); } public Void _call( Employee a1 ) { call( a1 ); return null; } public void call( Employee e ) { _e1 += e.salary; Frame_1.this._e1 += e.salary; } } } } // Classes needed by examples class List { private final T[] ts; private final Class c; public List( final Class c, final T... ts ) { this.c = c; this.ts = ts; } public void forEach( final Block b ) { for ( final T t : ts ) { b.call( t ); } } public List filter( final Filter f ) { final boolean[] bs = new boolean[ ts.length ]; int l = 0; for ( int i = 0; i < bs.length; i++ ) { if ( f.filter( ts[ i ] ) ) { bs[ i ] = true; l++; } else { bs[ i ] = false; } } final T[] newTs = (T[]) java.lang.reflect.Array.newInstance( c, l ); for ( int i = bs.length - 1; i >= 0; i-- ) { if ( bs[ i ] ) { l--; newTs[ l ] = ts[ i ]; } } return new List( c, newTs ); } public T get( final int i ) { return ts[ i ]; } public String toString() { return java.util.Arrays.toString( ts ); } } interface Block { void call( T t ); } interface Filter { boolean filter( T a ); } class Person { private static int last = 0; public final int size = last++; public String toString() { return "P(" + size + ")"; } } class Department { private static int last = 0; public final int num = last++; public String toString() { return "D(" + num + ")"; } } class Employee { private static int last = 0; public final int num = last++; public final Department dept; public int salary; public Employee( final Department dept, final int salary ) { this.dept = dept; this.salary = salary; } public String toString() { return "E(" + num + ", " + dept + ", " + salary + ")"; } } // Callables interface Callable0 { R _call(); } interface Callable1 { R _call( A1 a1 ); } interface Callable2 { R _call( A1 a1, A2 a2 ); } /** * Example of a Callable that uses primitives. Primitives boolean (B), double * (D), long (L), and void (V) could be supported. Naming convention is: * *
    *
  1. Callable
  2. *
  3. Followed by the number of arguments, n
  4. *
  5. Followed by the return type, if it is a primitive, represented by B, D, * L, or V, and
  6. *
  7. Finally the primitive arguments, also reresented by B, D, L, or V, but * in alphabetic order
  8. *
  9. If the Callable has more than one primitive argument then multiple * letters are used, e.g. LL represents 2 longs
  10. *
  11. If the Callable has a mixture of primitive and reference arguments then * the reference arguments go first in the _call method
  12. *
  13. The alphabetic sorting of the argument order reduces the number of * Callables; e.g. a Callable with a double and a long argument returning * void is the same as a Callable with a long and a double argument * returning void, both are Callable2VDL
  14. *
* *

The example below is a Callable with a void return type and a long * argument and a reference argument

*/ interface Callable2VL extends Callable2 { void _call2VL( A1 a1, long a2 ); } // Frames abstract class Frame1 { public E1 _e1; public Frame1( final E1 e1 ) { _e1 = e1; } } abstract class Frame2 extends Frame1 { public E2 _e2; public Frame2( final E1 e1, final E2 e2 ) { super( e1 ); _e2 = e2; } } From howard.lovatt at gmail.com Tue May 18 02:01:24 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 18 May 2010 19:01:24 +1000 Subject: First draft of translation document - contravariance Message-ID: I am guessing that the following will fail with the suggested MethodHandle translation (it is hard to say from the JSR292 literature): #String(Object) so = #String(final Object o) (o.toString()); #Object(String) os = so; Assuming it does fail, this failure may not be important since the use case is rare. Therefore this is post is a request for clarification rather than a criticism. -- Howard. From forax at univ-mlv.fr Tue May 18 02:10:18 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Tue, 18 May 2010 11:10:18 +0200 Subject: First draft of translation document - contravariance In-Reply-To: References: Message-ID: <4BF2597A.1020907@univ-mlv.fr> Le 18/05/2010 11:01, Howard Lovatt a ?crit : > I am guessing that the following will fail with the suggested > MethodHandle translation (it is hard to say from the JSR292 > literature): > > #String(Object) so = #String(final Object o) (o.toString()); > #Object(String) os = so; > > Assuming it does fail, this failure may not be important since the use > case is rare. Therefore this is post is a request for clarification > rather than a criticism. > > -- Howard. > > #String(Object) and #Object(String) will be erased to java.dyn.MethodHandle so it doesn't fail. BTW, jdk7 beta binaries already contain a preview of JSR 292 API, this is not the final API and there are some known bugs but you can already play with it. cheers, R?mi From brian.goetz at oracle.com Tue May 18 07:01:16 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 18 May 2010 10:01:16 -0400 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> Message-ID: <4BF29DAC.3010204@oracle.com> > "Additionally, we assume that the MethodHandle class will be extended > to provide a method asSam(Class sam) which will provide an optimized > form of injecting a SAM interface into a method handle." > > At the end of the day, doesn't that mean that an anonymous proxy class > will be created anyway? Nope! A bit of VM magic called "interface injection" allows this to be done without generating stub classes. Generating stub classes in the front-end compiler bloats up the application static footprint and increases program startup time. The VM magic bypasses these costs. From brian.goetz at oracle.com Tue May 18 07:03:20 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 18 May 2010 10:03:20 -0400 Subject: First draft of translation document In-Reply-To: <201005180905.44889.peter.levart@marand.si> References: <4BF17D74.6090104@oracle.com> <201005180905.44889.peter.levart@marand.si> Message-ID: <4BF29E28.2010307@oracle.com> > Just a note on section "10. Multiple lambdas per scope". While this > approach is logically correct and optimizes the number of Objects > created/classes used, it has a drawback that it might introduce memory > leaks. A long-lived lambda might hold on to the references that it didn't > actually capture in the source code. Yes, this is certainly a risk. Another similar risk is treating instance (reference) field capture as a capture of the final 'this' reference rather than simply capturing only the relevant reference fields. Like everything else, there is a tradeoff to be made -- potentially pinning more objects in memory vs reducing the cost of lambda capture. From neal at gafter.com Tue May 18 07:22:25 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 07:22:25 -0700 Subject: First draft of translation document In-Reply-To: References: Message-ID: On Tue, May 18, 2010 at 1:43 AM, Howard Lovatt wrote: > It is good to see a draft of how lambdas might be implemented, I think > that it makes it easier to discuss some issues and also clarifies some > parts of the specification. > > An alternative to using MethodHandles is to use a Callable interface > and then use inner classes to capture the 'frame'; Do you mean like section 6.2 of Brian's document? The VM does not "support" inner classes. Rather, inner classes are a language construct implemented by compiler "magic". Inner classes are translated by javac into ordinary (static) classes, with additional fields representing captured state and enclosing instances. Brian's document describes the translation of lambdas to primitives supported by the VM. From neal at gafter.com Tue May 18 07:58:46 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 07:58:46 -0700 Subject: First draft of translation document In-Reply-To: <4BF17D74.6090104@oracle.com> References: <4BF17D74.6090104@oracle.com> Message-ID: Brian- Am I correct to infer from this that the next iteration of the specification is likely to define SAM types as interfaces with a single method? -Neal On Mon, May 17, 2010 at 10:31 AM, Brian Goetz wrote: > We've posted a document describing a (somewhat naive) translation strategy for > translation of lambda expressions by javac here: > > ? http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > > > From brian.goetz at oracle.com Tue May 18 08:48:02 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 18 May 2010 11:48:02 -0400 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> Message-ID: <4BF2B6B2.3020103@oracle.com> That seems pretty likely. On 5/18/2010 10:58 AM, Neal Gafter wrote: > Brian- > > Am I correct to infer from this that the next iteration of the > specification is likely to define SAM types as interfaces with a > single method? > > -Neal > > On Mon, May 17, 2010 at 10:31 AM, Brian Goetz wrote: >> We've posted a document describing a (somewhat naive) translation strategy for >> translation of lambda expressions by javac here: >> >> http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf >> >> >> From brian.goetz at oracle.com Tue May 18 14:04:06 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 18 May 2010 17:04:06 -0400 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> <4BF1B4F0.6050500@oracle.com> Message-ID: <4BF300C6.50407@oracle.com> > - The closure$1 method is static yet seems to be trying to access the > "bottom" and "top" fields of the B2.Closure$1 class. Typo. In the "translation as inner class" approach, the closure methods should be instance methods. > - B2.Closure$1 implements Filter but presuming closure$1 was not meant > to be static, unless "closure$1" is the actual name of the one method in > the Filter SAM, "closure$1" is the wrong name. Presumably it should be > called "filter" or some such. Right, derived from the same cut and paste bug as above typo. > - Filter's signature is Filter, and its one method takes a T. that > method's erased signature would be (Ljava/lang/Object;)Z, and that's > what list.filter() will be working with, not (LPerson;)Z. Javac's > standard strategy here is to make filter(Person) the 'true' method and > generate a bridge method with signature filter(Object) which simply > wraps a call on to the true filter(Person), along with a cast. Given > that the most likely place that closure object will end up will use only > the bridge method, this seems needlessly inefficient. Is it perhaps > possible to generate only the filter(Object) variant? It would be possible, though the status quo it is not as inefficient as you might imagine. The bridge method filter(Object) dispatches to filter(Person), and in most cases class hierarchy analysis demonstrates that neither filter(Object) nor filter(Person) are overridden, and can be inlined by the VM. Even if filter(Person) is big (thus blowing the inlining budget), filter(Object) is not, and so it will be frequently inlined at the call site to filter(Object), eliminating the overhead you cite (also, inlining filter(Object) often exposes the opportunity to eliminate the cast check). Trust the VM! From forax at univ-mlv.fr Tue May 18 16:40:00 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 19 May 2010 01:40:00 +0200 Subject: First draft of translation document In-Reply-To: <4BF17D74.6090104@oracle.com> References: <4BF17D74.6090104@oracle.com> Message-ID: <4BF32550.4000401@univ-mlv.fr> Le 17/05/2010 19:31, Brian Goetz a ?crit : > We've posted a document describing a (somewhat naive) translation strategy for > translation of lambda expressions by javac here: > > http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > > Summary: - if there is no function types, lambda are handles by interfaces, in that case a lambda is created by a LDC (+ an optional bind) followed by a asSam() to avoid to create multiple inner classes - if function types exist, a lambda is a method handle (created by a LDC + an optional bind) and asSam() is used when interoperate which legacy code. A lambda can use - parameters,: in that case a LDC is sufficient - local variables: variables need to be bound to the method handle after a LDC - surrounding objects fields the surrounding objects need to be also bound. Up to here I'm okay. So for the JSR292 expert group, we have to correctly specifies asSam() and provides a polymorphic bindTo/insertArguments. Now the not agree part: Local variables can also be accessed by reference (with "shared"), in that case the compiler needs to construct a frame object to store the local variables, bind the frame to the method handle and retrieve the value after the call. I don't like it because: - there is no support offered by the VM for that, so each compiler (version of compilers) will choose a different ways to optimize or worst "perhaps optimize". Remember how the scheme to compile inner-classes changes over the time in javac. - it's not Java, as far as I know, there is no pass by reference in Java - the proposed scheme introduces a hidden allocation (perhaps !) - in term of design, we are trying to hide a mutable object, doesn't sound good. - the impact on the memory model is far from clear, one day shared vars will have to be specified in term of happen-before. - I don't want to explain why you can not use the keyword shared on a field, or why it doesn't work with anonymous/inner classes. I know that it's cool to have a feature like shared, above all if C# already have this feature but Java is not C# because the JVM is not a .Net VM. R?mi From reinier at zwitserloot.com Tue May 18 17:32:04 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Wed, 19 May 2010 02:32:04 +0200 Subject: First draft of translation document - contravariance In-Reply-To: <4BF2597A.1020907@univ-mlv.fr> References: <4BF2597A.1020907@univ-mlv.fr> Message-ID: Now I'm a bit confused. That sounds like this: #void(Integer) vi = #void(Integer i) { }; #void(String) vs = vi; would be legal as well which should be wrong, no? --Reinier Zwitserloot On Tue, May 18, 2010 at 11:10 AM, R?mi Forax wrote: > Le 18/05/2010 11:01, Howard Lovatt a ?crit : > > I am guessing that the following will fail with the suggested > > MethodHandle translation (it is hard to say from the JSR292 > > literature): > > > > #String(Object) so = #String(final Object o) (o.toString()); > > #Object(String) os = so; > > > > Assuming it does fail, this failure may not be important since the use > > case is rare. Therefore this is post is a request for clarification > > rather than a criticism. > > > > -- Howard. > > > > > > #String(Object) and #Object(String) will be erased to java.dyn.MethodHandle > so it doesn't fail. > > BTW, jdk7 beta binaries already contain a preview of JSR 292 API, > this is not the final API and there are some known bugs > but you can already play with it. > > cheers, > R?mi > > > > > From forax at univ-mlv.fr Tue May 18 17:37:00 2010 From: forax at univ-mlv.fr (=?UTF-8?B?UsOpbWkgRm9yYXg=?=) Date: Wed, 19 May 2010 02:37:00 +0200 Subject: First draft of translation document - contravariance In-Reply-To: References: <4BF2597A.1020907@univ-mlv.fr> Message-ID: <4BF332AC.6020405@univ-mlv.fr> Le 19/05/2010 02:32, Reinier Zwitserloot a ?crit : > Now I'm a bit confused. That sounds like this: > > #void(Integer) vi = #void(Integer i) { }; > #void(String) vs = vi; > > would be legal as well which should be wrong, no? > > --Reinier Zwitserloot It's not legal, MethodHandle are runtime time not compiler one. List is erased to List, #void(String) is erased to MethodHandle like List and List aren't compatible, #void(String) and #void(Integer) aren't compatible too. cheers, R?mi > > > > On Tue, May 18, 2010 at 11:10 AM, R?mi Forax > wrote: > > Le 18/05/2010 11:01, Howard Lovatt a ?crit : > > I am guessing that the following will fail with the suggested > > MethodHandle translation (it is hard to say from the JSR292 > > literature): > > > > #String(Object) so = #String(final Object o) (o.toString()); > > #Object(String) os = so; > > > > Assuming it does fail, this failure may not be important since > the use > > case is rare. Therefore this is post is a request for clarification > > rather than a criticism. > > > > -- Howard. > > > > > > #String(Object) and #Object(String) will be erased to > java.dyn.MethodHandle > so it doesn't fail. > > BTW, jdk7 beta binaries already contain a preview of JSR 292 API, > this is not the final API and there are some known bugs > but you can already play with it. > > cheers, > R?mi > > > > > From neal at gafter.com Tue May 18 17:37:37 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 17:37:37 -0700 Subject: First draft of translation document In-Reply-To: <4BF32550.4000401@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> Message-ID: On Tue, May 18, 2010 at 4:40 PM, R?mi Forax wrote: > Now the not agree part: > Local variables can also be accessed by reference (with "shared"), > in that case the compiler needs to construct a frame object to store the > local variables, > bind the frame to the method handle and retrieve the value after the call. > > I don't like it because: > - there is no support offered by the VM for that, so each compiler > (version of compilers) > will choose a different ways to optimize or worst "perhaps optimize". > Remember how the scheme to compile inner-classes changes over the > time in javac. > Language features are not to be defined by the features of the VM. In this case, the implementation strategy is a contract between the compiler and itself. There is no interoperability issue between languages and compilers that may do it in ways that differ in detail. > - it's not Java, as far as I know, there is no pass by reference in Java > This is not proposing a pass-by-reference language feature. It is describing a way to compile code that references ordinary mutable variables. Mutable variables are definitely part of and in the spirit of Java. - the impact on the memory model is far from clear, one day shared > vars will have to > be specified in term of happen-before. > Indeed, that is already the case for local variables. Final local variables can already be shared among threads, and the current memory model does not specify the behavior. They happen to be implemented by Java compilers as fields, which is the only available implementation strategy. The behavior for both final and non-final variables can be specified by reference to existing specification text describing the behavior for fields. From forax at univ-mlv.fr Tue May 18 18:02:57 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 19 May 2010 03:02:57 +0200 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> Message-ID: <4BF338C1.50202@univ-mlv.fr> Le 19/05/2010 02:37, Neal Gafter a ?crit : > On Tue, May 18, 2010 at 4:40 PM, R?mi Forax > wrote: > > Now the not agree part: > Local variables can also be accessed by reference (with "shared"), > in that case the compiler needs to construct a frame object to > store the > local variables, > bind the frame to the method handle and retrieve the value after > the call. > > I don't like it because: > - there is no support offered by the VM for that, so each compiler > (version of compilers) > will choose a different ways to optimize or worst "perhaps > optimize". > Remember how the scheme to compile inner-classes changes over the > time in javac. > > > Language features are not to be defined by the features of the VM. Agree in general, but not in this specific case. The frame object or any equivalent data structure should be managed by the VM, it's a stack allocated data structure. There is no need of an object header or a vtable for such data structure. > In this case, the implementation strategy is a contract between the > compiler and itself. There is no interoperability issue between > languages and compilers that may do it in ways that differ in detail. There are always interop issues, some not so stupid tools crawle the bytecode, or some not so stupid users use reflection. The frame object will appear as parameter of the function that will be used to create the lambda. > > - it's not Java, as far as I know, there is no pass by reference > in Java > > > This is not proposing a pass-by-reference language feature. It is > describing a way to compile code that references ordinary mutable > variables. Mutable variables are definitely part of and in the spirit > of Java. Threre aren't that ordinary because you have to create a new keyword or if you prefer a new semantics for those kind of variables. > > - the impact on the memory model is far from clear, one day shared > vars will have to > be specified in term of happen-before. > > > Indeed, that is already the case for local variables. Final local > variables can already be shared among threads, and the current memory > model does not specify the behavior. They happen to be implemented by > Java compilers as fields, which is the only available implementation > strategy. The behavior for both final and non-final variables can be > specified by reference to existing specification text describing the > behavior for fields. final locals variables aren't translated to fields but final fields. Final fields haven't the same semantics than ordinary fields hence the keyword "final". I agree that final local variable aren't currently described in the spec and should but that doesn't solve the problem of the semantics of shared local variables. If the 1.8 VM comes with a way to declare a frame data structure or any equivalent stuff and if someone comes with a clear semantics, I will be okay to introduce with shared vars. R?mi From neal at gafter.com Tue May 18 20:31:06 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 20:31:06 -0700 Subject: First draft of translation document In-Reply-To: <4BF338C1.50202@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> Message-ID: On Tue, May 18, 2010 at 6:02 PM, R?mi Forax wrote: >> Language features are not to be defined by the features of the VM. > > Agree in general, but not in this specific case. > The frame object or any equivalent data structure should be managed by the > VM, > it's a stack allocated data structure. There is no need of an object header > or a vtable > for such data structure. These frame objects are not stack allocated. They must be managed by the GC. Thus, an object header is required. >> This is not proposing a pass-by-reference language feature.? It is >> describing a way to compile code that references ordinary mutable >> variables.? Mutable variables are definitely part of and in the spirit of >> Java. > > Threse aren't that ordinary because you have to create a new keyword or if > you prefer a new semantics > for those kind of variables. Neither is needed. While project lambda may elect to have a new keyword for other reasons, it is not necessary. Neither are new semantics required. > final locals variables aren't translated to fields but final fields. Final > fields haven't the same semantics > than ordinary fields hence the keyword "final". > I agree that final local variable aren't currently described in the spec and > should but that doesn't solve the problem > of the semantics of shared local variables. Agreed: final locals should follow the semantics of final fields, and mutable locals should follow the semantics of mutable fields. From neal at gafter.com Tue May 18 21:20:33 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 21:20:33 -0700 Subject: First draft of translation document In-Reply-To: <4BF1B4F0.6050500@oracle.com> References: <4BF17D74.6090104@oracle.com> <4BF1B4F0.6050500@oracle.com> Message-ID: On Mon, May 17, 2010 at 2:28 PM, Brian Goetz wrote: > This is quite common when activities evolve in parallel -- one must make > assumptions (or wishful thinking) about the future course of other > coincident activities. > All very reasonable, particularly in the early phases of a project. But the last TL integration before feature-complete is Friday. Do you expect to meet the schedule? If not, do you think it more likely that project lambda will be removed from the scope of SE 7 (perhaps freeing up resources for other SE 7 work), or that the schedule will slip (enabling a more thorough investigation of the design choices)? From neal at gafter.com Tue May 18 21:39:15 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 18 May 2010 21:39:15 -0700 Subject: Reading the Tea Leaves (who's working on Project Lambda) Message-ID: I noticed that two recently published documents were http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf and http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf Both list Brian Goetz as author. The translation document is in Maurizio Cimadamore's code review area. The defender methods document is in Joe Darcy's code review area. I don't expect Oracle employees will be authorized to discuss resource allocation, but I take this as an encouraging sign. From forax at univ-mlv.fr Wed May 19 02:35:11 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 19 May 2010 11:35:11 +0200 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> Message-ID: <4BF3B0CF.8050809@univ-mlv.fr> Le 19/05/2010 05:31, Neal Gafter a ?crit : > On Tue, May 18, 2010 at 6:02 PM, R?mi Forax wrote: > >>> Language features are not to be defined by the features of the VM. >>> >> Agree in general, but not in this specific case. >> The frame object or any equivalent data structure should be managed by the >> VM, >> it's a stack allocated data structure. There is no need of an object header >> or a vtable >> for such data structure. >> > These frame objects are not stack allocated. They must be managed by > the GC. Thus, an object header is required. > The whole point of asSam() is to try to avoid the static footprint that you currently have with anonymous classes. If the frame object is not know by the VM, the compiler have to generate a specific class for each frame object thus we are falling in the same trap as anonymous classes. > >>> This is not proposing a pass-by-reference language feature. It is >>> describing a way to compile code that references ordinary mutable >>> variables. Mutable variables are definitely part of and in the spirit of >>> Java. >>> >> Threse aren't that ordinary because you have to create a new keyword or if >> you prefer a new semantics >> for those kind of variables. >> > Neither is needed. While project lambda may elect to have a new > keyword for other reasons, it is not necessary. Neither are new > semantics required. > The problem with shared variables is that you break the assumption that you have sequential ordering of local variables. I don't see why we should offer a feature with such semantics. void f() { shared String s = "hello"; Utils.perhapsRunInAnotherThread(#() { System.out.println(s); // may or may not prints null }); } The Java memory model is sufficiently complicated to not add more subtilities. [...] R?mi From neal at gafter.com Wed May 19 08:05:58 2010 From: neal at gafter.com (Neal Gafter) Date: Wed, 19 May 2010 08:05:58 -0700 Subject: First draft of translation document In-Reply-To: <4BF3B0CF.8050809@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> Message-ID: On Wed, May 19, 2010 at 2:35 AM, R?mi Forax wrote: >> These frame objects are not stack allocated. ?They must be managed by >> the GC. ?Thus, an object header is required. > > The whole point of asSam() is to try to avoid the static footprint that you > currently have with anonymous classes. > If the frame object is not know by the VM, the compiler have to generate a > specific class for each frame object > thus we are falling in the same trap as anonymous classes. I don't know what you mean by "known by the VM", or how a separate VM feature could make any difference, since these frame object must be heap allocated. Perhaps you're advocating some kind of structural types at the VM level? > The problem with shared variables is that you break the assumption > that you have sequential ordering of local variables. > I don't see why we should offer a feature with such semantics. > > void f() { > ?shared String s = "hello"; > ?Utils.perhapsRunInAnotherThread(#() { > ? ?System.out.println(s); // may or may not prints null > ?}); > } The initialization of the variable s "happens before" the thread is even created, so there is no race condition. This program always prints "hello". This is no different than if s had been a field. From brian.goetz at oracle.com Wed May 19 08:34:13 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 19 May 2010 11:34:13 -0400 Subject: First draft of translation document In-Reply-To: <4BF32550.4000401@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> Message-ID: <4BF404F5.8010103@oracle.com> > So for the JSR292 expert group, we have to correctly specifies > asSam() and provides a polymorphic bindTo/insertArguments. Well, I'd say its a "kind request" to the JSR-292 expert group rather than a "demand" :) But yes, this specific translation strategy would benefit from some specific help from MethodHandle. > Now the not agree part: > Local variables can also be accessed by reference (with "shared"), Let's set aside the question of how we refer to captured mutable variables for now -- this is a language issue which we will surely return to. Let's just assume for this discussion that the translation approach needs to accomodate this use case (and we later choose to disallow it, then the type 1/2/3 distinction becomes merely type 1/2.) > in that case the compiler needs to construct a frame object to store the > local variables, > bind the frame to the method handle and retrieve the value after the call. > > I don't like it because: > - there is no support offered by the VM for that, so each compiler > (version of compilers) > will choose a different ways to optimize or worst "perhaps optimize". I don't like the Frame class either, but without additional VM support (which is unlikely to come from JSR-292 in the JDK 7 time frame) I'm not sure what the alternatives are. In an example like: int total = 0; list.forEach(#(Person p) { total += p.getFoo(); }); There are really two cases: - The closure may escape from forEach(), and be saved for later or called from another thread; - The closure will not escape from forEach() In the escaping case, I don't see how we can avoid the Frame even with VM support -- we need to use the Frame to extend the dynamic scope of the captured variables beyond their lexical scope. In the non-escaping case, I think what you are appealing to is that total should live on the stack. I think what happens here comes down to whether the VM can inline all the way through from the caller to forEach() and back through the closure. If it can, then escape analysis eliminates the frame, and the locals can be hoisted into registers, and all the mechanics of capturing the closure are folded away. > - the proposed scheme introduces a hidden allocation (perhaps !) I'm OK with that. > - the impact on the memory model is far from clear, one day shared > vars will have to > be specified in term of happen-before. For sure. The JLS describes seven types of variables (though the distinction between two of them is pretty tenuous). A "shared" local variable is definitely an eighth kind of variable. I am in favor of making this distinction explicit so that the memory model semantics are clear. From forax at univ-mlv.fr Wed May 19 09:40:58 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 19 May 2010 18:40:58 +0200 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> Message-ID: <4BF4149A.3090809@univ-mlv.fr> Le 19/05/2010 17:05, Neal Gafter a ?crit : > On Wed, May 19, 2010 at 2:35 AM, R?mi Forax wrote: > >>> These frame objects are not stack allocated. They must be managed by >>> the GC. Thus, an object header is required. >>> >> The whole point of asSam() is to try to avoid the static footprint that you >> currently have with anonymous classes. >> If the frame object is not know by the VM, the compiler have to generate a >> specific class for each frame object >> thus we are falling in the same trap as anonymous classes. >> > I don't know what you mean by "known by the VM", or how a separate VM > feature could make any difference, since these frame object must be > heap allocated. Perhaps you're advocating some kind of structural > types at the VM level? > yes something like that. > >> The problem with shared variables is that you break the assumption >> that you have sequential ordering of local variables. >> I don't see why we should offer a feature with such semantics. >> >> void f() { >> shared String s = "hello"; >> Utils.perhapsRunInAnotherThread(#() { >> System.out.println(s); // may or may not prints null >> }); >> } >> > The initialization of the variable s "happens before" the thread is > even created, so there is no race condition. This program always > prints "hello". This is no different than if s had been a field. > I am not a concurrency guru but I think you are wrong. The field s of the Frame can be printed by another thread before it is initialization. The local variable s will be correctly initialized but not the corresponding field in Frame. R?mi From brian.goetz at oracle.com Wed May 19 10:08:38 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 19 May 2010 13:08:38 -0400 Subject: First draft of translation document In-Reply-To: <4BF4149A.3090809@univ-mlv.fr> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> <4BF4149A.3090809@univ-mlv.fr> Message-ID: <4BF41B16.20801@oracle.com> >>> void f() { >>> shared String s = "hello"; >>> Utils.perhapsRunInAnotherThread(#() { >>> System.out.println(s); // may or may not prints null >>> }); >>> } >>> >> The initialization of the variable s "happens before" the thread is >> even created, so there is no race condition. This program always >> prints "hello". This is no different than if s had been a field. >> > > I am not a concurrency guru but I think you are wrong. > The field s of the Frame can be printed by another thread before it is > initialization. > The local variable s will be correctly initialized but not the > corresponding field in Frame. Since 'shared' does not yet exist in the language, we don't know what its semantics are. Therefore Neal cannot be wrong! (He also cannot be right.) But lets imagine there was such a language feature, and it had a specification. Maybe shared variables are implicitly volatile; maybe shared variables can be declared explicitly volatile in addition to shared. Reasoning about either case is not so easy. We probably have to assume that Utils is written such that the closure is not passed from thread to thread via a data race; that there has to be a happens-before between some point inside perhapsRunInAnotherThread (call it X) and the execution of the closure body in the other thread (call it Y). With this assumption, in both cases there is no data race between the initialization and the use, since the initialization happens-before X (and by transitivity, it happens-before the use at Y). If the assumption fails to hold, making s volatile will generate a happens-before ordering even if the closure is passed via a data race, but calls into question other aspects of the closure's internal state (such as the frame pointer.) The same argument applies in reverse: void f() { shared String s; Utils.perhapsRunInAnotherThread(#() { s = "blarg"; }); System.out.println(s); } Where we now need a happens-before between the write in the other thread and the read in the calling thread. Note that this is totally outside the semantics of closures; it is about the behavior of Utils. So now we find ourselves reasoning about the JMM characteristics of the dispatch logic in Utils, which is of course opaque and nearly always underspecified. Note also that the JSR-292 EG may want to make stronger representations about whether the various MH combinators behave effectively like setting final fields in a constructor, or whether the internal state in the combinator nodes are ordinary nonvolatile mutable state. From howard.lovatt at gmail.com Wed May 19 17:34:16 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 20 May 2010 10:34:16 +1000 Subject: First draft of translation document In-Reply-To: References: Message-ID: Comments in-line On 19 May 2010 00:22, Neal Gafter wrote: > On Tue, May 18, 2010 at 1:43 AM, Howard Lovatt wrote: >> It is good to see a draft of how lambdas might be implemented, I think >> that it makes it easier to discuss some issues and also clarifies some >> parts of the specification. >> >> An alternative to using MethodHandles is to use a Callable interface >> and then use inner classes to capture the 'frame'; > > Do you mean like section 6.2 of Brian's document? Similar but using an interface instead of a Method Handle and putting all the transformation inside a single frame, so that only one object is created per lambda > The VM does not "support" inner classes. ?Rather, inner classes are a > language construct implemented by compiler "magic". ?Inner classes are > translated by javac into ordinary (static) classes, with additional > fields representing captured state and enclosing instances. ?Brian's > document describes the translation of lambdas to primitives supported > by the VM. Sure - it is just a convenient way to express the transformation. I was assuming that everyone was familiar with this. -- Howard. From howard.lovatt at gmail.com Wed May 19 18:09:25 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Thu, 20 May 2010 11:09:25 +1000 Subject: First draft of translation document Message-ID: R?mi Forax wrote: >Le 19/05/2010 05:31, Neal Gafter a ?crit : >> On Tue, May 18, 2010 at 6:02 PM, R?mi Forax wrote: [snip] > The problem with shared variables is that you break the assumption > that you have sequential ordering of local variables. > I don't see why we should offer a feature with such semantics. > > void f() { > shared String s = "hello"; > Utils.perhapsRunInAnotherThread(#() { > System.out.println(s); // may or may not prints null > }); > } > > The Java memory model is sufficiently complicated to not add more > subtilities. This is one of the reasons I wrote an alternate translation, if you are going to have to have a stack frame object, multiple binds to the MethodHandles, interface injection to the MethodHandle, then I am speculating that a single Frame object that does the lot will be faster: private static class Frame_1 extends Frame1 implements Callable0V { Frame_1( final String s ) { super( s ); } public Void _call() { _call0V(); return null; } public void _call0V() { System.out.println( _e1 ); } } void f() { final Frame_1 frame_1 = new Frame_1( "hello" ); Utils.perhapsRunInAnotherThread( frame_1 ); } -- Howard. From nathan.bryant at linkshare.com Thu May 20 08:03:24 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Fri, 21 May 2010 00:03:24 +0900 Subject: First draft of translation document References: Message-ID: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> Howard wrote: [snip] ... > >private static class Frame_1 extends Frame1 implements Callable0V { > Frame_1( final String s ) { super( s ); } > > public Void _call() { _call0V(); return null; } > public void _call0V() { System.out.println( _e1 ); } >} Not much different from an inner class. This example does not describe what to do about multiple closures in the same scope. With regard to the recent proposals, the advantages of interface injection are clear. I do not see any clear advantage to MethodHandle with bind for partial application (but maybe I'm just missing something) From reinier at zwitserloot.com Thu May 20 08:12:43 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Thu, 20 May 2010 17:12:43 +0200 Subject: First draft of translation document In-Reply-To: <4BF41B16.20801@oracle.com> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> <4BF4149A.3090809@univ-mlv.fr> <4BF41B16.20801@oracle.com> Message-ID: Reasoning about this for the VM gets a lot easier if the VM knows for sure that the closure will not escape from its current stack frame. In other words, in code like this: list.filter(#(Person p) (p.age() < 20)); assuming for a moment that filter is 'eager', that closure won't escape. It doesn't end up in a field somewhere, it doesn't run in another thread. If the GC runs immediately following the termination of this method (and the closure is represented as some sort of object), it would be eligible for GC. If this is indeed the case there is no need to mark any shared variables as volatile. It may be possible to allocate on the stack whatever frame objects are required. Perhaps if in future "long returns" are added (the ability to have break / continue / return retain their meaning as if the code was written in the scope from the method itself, not from the closure), any such activities cease to make sense if the closure escapes its stack context, but if the VM knows for sure the closure won't escape it may be able to optimize the way those constructs work (better than the BGGA exception mechanism). But not just the VM benefits, so does the programmer. By knowing that a certain closure does not escape, the programmer has a much easier time reasoning about the effects of sharing a non-final variable between closure and hosting block. BGGA had something somewhat similar in the 'safe' vs. 'unsafe' closures concept. Would it be possible to support some sort of marker on a method parameter that means: "I will ensure this parameter will not escape", which is enforced by the compiler and verified by the verifier? This way the aforementioned "filter" method could include this marker on the 1 closure parameter it takes, and from there the JVM itself and javac during compilation of "list.filter(#(Person p) (p.age() < 20));" can react knowing that this closure won't escape. For example, the compiler may silently "share" mutable variables knowing the pragmatic different is moot, at least for the programmer, but if this is NOT a guaranteed-no-escape kind of closure, it could require an explicit "shared" keyword. NB: "Escaping" is defined as: Assigning the closure to anything, sharing with an anonymous inner class or method local class (or potentially escaping closure), using the variable as a parameter, unless used as a parameter to a method where that parameter is also marked 'no escape guaranteed'. --Reinier Zwitserloot On Wed, May 19, 2010 at 7:08 PM, Brian Goetz wrote: > >>> void f() { > >>> shared String s = "hello"; > >>> Utils.perhapsRunInAnotherThread(#() { > >>> System.out.println(s); // may or may not prints null > >>> }); > >>> } > >>> > >> The initialization of the variable s "happens before" the thread is > >> even created, so there is no race condition. This program always > >> prints "hello". This is no different than if s had been a field. > >> > > > > I am not a concurrency guru but I think you are wrong. > > The field s of the Frame can be printed by another thread before it is > > initialization. > > The local variable s will be correctly initialized but not the > > corresponding field in Frame. > > Since 'shared' does not yet exist in the language, we don't know what its > semantics are. Therefore Neal cannot be wrong! (He also cannot be right.) > > But lets imagine there was such a language feature, and it had a > specification. Maybe shared variables are implicitly volatile; maybe > shared > variables can be declared explicitly volatile in addition to shared. > > Reasoning about either case is not so easy. We probably have to assume > that > Utils is written such that the closure is not passed from thread to thread > via > a data race; that there has to be a happens-before between some point > inside > perhapsRunInAnotherThread (call it X) and the execution of the closure body > in > the other thread (call it Y). > > With this assumption, in both cases there is no data race between the > initialization and the use, since the initialization happens-before X (and > by > transitivity, it happens-before the use at Y). > > If the assumption fails to hold, making s volatile will generate a > happens-before ordering even if the closure is passed via a data race, but > calls into question other aspects of the closure's internal state (such as > the > frame pointer.) > > The same argument applies in reverse: > > void f() { > shared String s; > Utils.perhapsRunInAnotherThread(#() { > s = "blarg"; > }); > System.out.println(s); > } > > Where we now need a happens-before between the write in the other thread > and > the read in the calling thread. Note that this is totally outside the > semantics of closures; it is about the behavior of Utils. So now we find > ourselves reasoning about the JMM characteristics of the dispatch logic in > Utils, which is of course opaque and nearly always underspecified. > > Note also that the JSR-292 EG may want to make stronger representations > about > whether the various MH combinators behave effectively like setting final > fields in a constructor, or whether the internal state in the combinator > nodes > are ordinary nonvolatile mutable state. > > > From brian.goetz at oracle.com Thu May 20 08:32:34 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 May 2010 11:32:34 -0400 Subject: First draft of translation document In-Reply-To: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: <4BF55612.30508@oracle.com> > With regard to the recent proposals, the advantages of interface > injection are clear. I do not see any clear advantage to MethodHandle > with bind for partial application (but maybe I'm just missing something) Yes, you're missing something: optimization! To take a simple example, lets say I have a function f(x, y) { if (x != null) x.foo() else y.foo() } If I partially apply x, now x is a constant for purposes of compilation. So if I partially apply a null x argument, the test and branch get dead-code-eliminated and it reduces to f(y) { y.foo() } This may not seem like a big deal, but partial application gives the VM way more information -- type information, nullity information, array bounds information -- with which it can perform all sorts of optimizations (type sharpening which leads to better inlining, null check elimination, array bounds check elimination, dead code elimination, etc). From brian.goetz at oracle.com Thu May 20 08:40:52 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 May 2010 11:40:52 -0400 Subject: First draft of translation document In-Reply-To: References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> <4BF4149A.3090809@univ-mlv.fr> <4BF41B16.20801@oracle.com> Message-ID: <4BF55804.5040200@oracle.com> > Reasoning about this for the VM gets a lot easier if the VM knows for > sure that the closure will not escape from its current stack frame. In > other words, in code like this: > > list.filter(#(Person p) (p.age() < 20)); > > assuming for a moment that filter is 'eager', that closure won't escape. There's a bigger assumption here: that filter is explicitly sequential. But I'd like it if filter() had the option to do the filtering in parallel in a fork-join pool! Simplifying library-based parallelism was one of the explicit goals for this effort. In any case this is the easy case, a "type 1". Here, the closure is a "pure function" so all sorts of good things can happen. From alex.blewitt at gmail.com Thu May 20 09:32:16 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 20 May 2010 17:32:16 +0100 Subject: First draft of translation document In-Reply-To: <4BF55804.5040200@oracle.com> References: <4BF17D74.6090104@oracle.com> <4BF32550.4000401@univ-mlv.fr> <4BF338C1.50202@univ-mlv.fr> <4BF3B0CF.8050809@univ-mlv.fr> <4BF4149A.3090809@univ-mlv.fr> <4BF41B16.20801@oracle.com> <4BF55804.5040200@oracle.com> Message-ID: On 20 May 2010, at 16:40, Brian Goetz wrote: >> Reasoning about this for the VM gets a lot easier if the VM knows for >> sure that the closure will not escape from its current stack frame. >> In >> other words, in code like this: >> >> list.filter(#(Person p) (p.age() < 20)); >> >> assuming for a moment that filter is 'eager', that closure won't >> escape. > > There's a bigger assumption here: that filter is explicitly > sequential. But > I'd like it if filter() had the option to do the filtering in > parallel in a > fork-join pool! Simplifying library-based parallelism was one of > the explicit > goals for this effort. > > In any case this is the easy case, a "type 1". Here, the closure is > a "pure > function" so all sorts of good things can happen It's not a closure; it's a lambda. There is no local state to capture; so it's a closed term already. It's only a closure if it captures lexical scope outside the function. Alex From nathan.bryant at linkshare.com Thu May 20 10:32:38 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Fri, 21 May 2010 02:32:38 +0900 Subject: First draft of translation document References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> Message-ID: <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> Brian, Thanks for reiterating this. Can that sort of thing be made safe from a permgen churn perspective? Seems like it can't kick in unless the VM sees a runtime profile where functions are always constructed (partially applied) from a small, consistent set of arguments. More generally: at least in principle, the VM has analogous information available to it for every object that is constructed with final fields, but there must be some reasons why it doesn't do the analogous optimization there. (i.e. automatically generate specialized subclasses wherever it feels like, and dead code eliminate everything that touches a final field!) -----Original Message----- From: Brian Goetz [mailto:brian.goetz at oracle.com] Sent: Thursday, May 20, 2010 11:33 AM To: Nathan Bryant Cc: Howard Lovatt; lambda-dev at openjdk.java.net Subject: Re: First draft of translation document > With regard to the recent proposals, the advantages of interface > injection are clear. I do not see any clear advantage to MethodHandle > with bind for partial application (but maybe I'm just missing something) Yes, you're missing something: optimization! To take a simple example, lets say I have a function f(x, y) { if (x != null) x.foo() else y.foo() } If I partially apply x, now x is a constant for purposes of compilation. So if I partially apply a null x argument, the test and branch get dead-code-eliminated and it reduces to f(y) { y.foo() } This may not seem like a big deal, but partial application gives the VM way more information -- type information, nullity information, array bounds information -- with which it can perform all sorts of optimizations (type sharpening which leads to better inlining, null check elimination, array bounds check elimination, dead code elimination, etc). From brian.goetz at oracle.com Thu May 20 10:37:24 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 May 2010 13:37:24 -0400 Subject: First draft of translation document In-Reply-To: <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: <4BF57354.4000902@oracle.com> > Can that sort of thing be made safe from a permgen churn perspective? Permgen is an issue with nominal class metadata. But method handle activity happen in the actively managed memory pools, because method handles are anonymous. From nathan.bryant at linkshare.com Thu May 20 10:41:34 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Fri, 21 May 2010 02:41:34 +0900 Subject: First draft of translation document References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> <4BF57354.4000902@oracle.com> Message-ID: <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> In that case, if the VM were to decide to generate an optimized specialization for a partially applied function, where does the generated code go? A MethodHandle may be data, but seems like code is code. Are you saying the code goes on the normal heap, then? -----Original Message----- From: Brian Goetz [mailto:brian.goetz at oracle.com] Sent: Thursday, May 20, 2010 1:37 PM To: Nathan Bryant Cc: Howard Lovatt; lambda-dev at openjdk.java.net Subject: Re: First draft of translation document > Can that sort of thing be made safe from a permgen churn perspective? Permgen is an issue with nominal class metadata. But method handle activity happen in the actively managed memory pools, because method handles are anonymous. From brian.goetz at oracle.com Thu May 20 10:43:52 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 May 2010 13:43:52 -0400 Subject: First draft of translation document In-Reply-To: <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> <4BF57354.4000902@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: <4BF574D8.90307@oracle.com> VMs maintain many actively managed regions, such as caches for generated code, metadata derived from bytecode (such as CFG and SSA reductions), etc, that live outside what most java developers think of as "the heap" but don't necessarily live in "perm gen." On 5/20/2010 1:41 PM, Nathan Bryant wrote: > In that case, if the VM were to decide to generate an optimized > specialization for a partially applied function, where does the > generated code go? A MethodHandle may be data, but seems like code is > code. > > Are you saying the code goes on the normal heap, then? > > -----Original Message----- > From: Brian Goetz [mailto:brian.goetz at oracle.com] > Sent: Thursday, May 20, 2010 1:37 PM > To: Nathan Bryant > Cc: Howard Lovatt; lambda-dev at openjdk.java.net > Subject: Re: First draft of translation document > >> Can that sort of thing be made safe from a permgen churn perspective? > > Permgen is an issue with nominal class metadata. But method handle > activity > happen in the actively managed memory pools, because method handles are > anonymous. > From brian.goetz at oracle.com Fri May 21 10:34:41 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 21 May 2010 13:34:41 -0400 Subject: OpenJDK Lambda workspace is now open Message-ID: <4BF6C431.9090508@oracle.com> An OpenJDK workspace for Project Lambda has been created: http://hg.openjdk.java.net/lambda/lambda As of today is it a clone of JDK7-b94. From alex.blewitt at gmail.com Sun May 23 08:03:15 2010 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Sun, 23 May 2010 16:03:15 +0100 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BF14F2E.5010701@univ-mlv.fr> References: <4BEDD9E9.7050300@oracle.com> <4BF14B8F.1090206@oracle.com> <4BF14F2E.5010701@univ-mlv.fr> Message-ID: On 17 May 2010, at 15:14, R?mi Forax wrote: > Le 17/05/2010 15:58, Brian Goetz a ?crit : >>> and have all JDK List-classes implement List2 instead of only List. >>> They encourage the use of List2 in the API Doc. >>> >>> There would have been no compatibility issues at all. Programmers >>> would have adopted List2 whenenver they were writing new code. >>> >> And in user code, people would have inserted casts to List2 whenever they >> encountered a List, sometimes with an instanceof check first, sometimes >> without. That would not be good for the readability or maintainability of >> Java code. >> > > Eclipse developers do something similar. > I was not happy when I tried to understand ITextViewer6: > http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/text/ITextViewerExtension6.html > > I am not a big fan of having to understand all the history of > an API before being able to use it. A friend of mine calls that: > archeological programming. One doesn't have to understand history to be able to use ITextViewer6; one can just use methods defined therein. There's a distinction between an interface which is indented to be used by clients, and one which is intended to be implemented in clients. The former case permits the addition of methods; the latter does not. The evolution by I..n interfaces permits both, albeit somewhat ugly. However, I have concerns with the defender methods in more general terms. Putting an alias to a static method is akin to permitting code in an interface; what happens in the following case: public interface A { extension int stuff() default AA.stuff; } public interface B { extension int stuff() default BB.stuff; } public class AB implements A, B { // where does AB.stuff() go? } This is the classic 'diamond problem' that is experienced with multiple implementation inheritance. Unfortunately, the proposal document (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) brushes this under the covers (5.1) with a 'should throw an exception' at this point. This is pretty silent, outside of any compiler warnings, and is definitely a change of behaviour. Even without that, I don't see that any consideration has been given to what happens to already existing methods which are used prior to this change. For example, consider the lowly 'filter' method - some implementations may perform an in-place filter, returning 'true' or 'false' to indicate if any changes were allowed, whereas others may return a new copy of the data structure with elements that match the filter. What if a generic 'filter' method is then defaulted to the interface? public A implements DataStructure { public boolean filter(FilterSam filter) {...} } public B implements DataStructure { public DataStructure filter(FilterSam filter) {...} } // Later, someone makes the change: public interface DataStructure { extension DataStructure filter(FilterSam filter) default Default.filter; } Now we have a situation where previously there was no common filter() signature, there is now. The problem is that class A may well have been written long before the existence of B, but we have now introduced a situation where client code invoking A.filter() is presented with the return value of a different type to which it expects. The key problem is that the draft spec has no observations of what should happen when the extension method is of a different signature (i.e. not covariant in the return types). It seems to me that the first round of changes to the Collections classes are going to be unaffected by this concern purely because there is no super lambda type for existing methods to have already implemented. Alex From brian.goetz at oracle.com Sun May 23 08:11:31 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 23 May 2010 11:11:31 -0400 Subject: Fwd: OpenJDK Lambda workspace is now open Message-ID: <4BF945A3.8060107@oracle.com> This seems to have gotten eaten by the mailer daemon: Date: Fri, 21 May 2010 13:34:41 -0400 From: Brian Goetz To: lambda-dev at openjdk.java.net An OpenJDK workspace for Project Lambda has been created: http://hg.openjdk.java.net/lambda/lambda As of today is it a clone of JDK7-b94. From howard.lovatt at gmail.com Sun May 23 17:30:38 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 24 May 2010 10:30:38 +1000 Subject: First draft of translation document In-Reply-To: <4BF574D8.90307@oracle.com> References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> <4BF57354.4000902@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> <4BF574D8.90307@oracle.com> Message-ID: This, MethodHandle efficiency, is only true if you don't need a separate frame object, once you need a frame object then the overhead of a method handle can be avoided by using the frame for everything. This was Remi Forax's original point. An interesting idea would be to change the semantics of an *anonymous* inner class so that they could be garbage collected without having to have first collected their class loader. Since an anonymous inner class can only have one instance this change won't break ordinary code. Though it will break reflective code that uses the inner class. This change, collection of anonymous inner classes, would help with the frame object. On 21 May 2010 03:43, Brian Goetz wrote: > VMs maintain many actively managed regions, such as caches for generated > code, metadata derived from bytecode (such as CFG and SSA reductions), etc, > that live outside what most java developers think of as "the heap" but don't > necessarily live in "perm gen." > > On 5/20/2010 1:41 PM, Nathan Bryant wrote: >> >> In that case, if the VM were to decide to generate an optimized >> specialization for a partially applied function, where does the >> generated code go? A MethodHandle may be data, but seems like code is >> code. >> >> Are you saying the code goes on the normal heap, then? >> >> -----Original Message----- >> From: Brian Goetz [mailto:brian.goetz at oracle.com] >> Sent: Thursday, May 20, 2010 1:37 PM >> To: Nathan Bryant >> Cc: Howard Lovatt; lambda-dev at openjdk.java.net >> Subject: Re: First draft of translation document >> >>> Can that sort of thing be made safe from a permgen churn perspective? >> >> Permgen is an issue with nominal class metadata. ?But method handle >> activity >> happen in the actively managed memory pools, because method handles are >> anonymous. >> > -- -- Howard. From howard.lovatt at gmail.com Sun May 23 17:36:16 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 24 May 2010 10:36:16 +1000 Subject: First draft of translation document In-Reply-To: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: If you look at the class D example in: http://mail.openjdk.java.net/pipermail/lambda-dev/2010-May/001364.html It shows multiple captures using a frame object that also contains the lambda. As an aside the main difference in the alternate translation is that it only contains one object, the frame object, that does both the variable capture and is itself the lambda. The other translation has two objects, one to capture the frame and one for the lambda. On 21 May 2010 01:03, Nathan Bryant wrote: > > > Howard wrote: > [snip] > > ... >> >>private static class Frame_1 extends Frame1 implements > Callable0V { >> ?Frame_1( final String s ) { super( s ); } >> >> ?public Void _call() { _call0V(); return null; } >> ?public void _call0V() { System.out.println( _e1 ); } >>} > > Not much different from an inner class. This example does not describe > what to do about multiple closures in the same scope. > > With regard to the recent proposals, the advantages of interface > injection are clear. I do not see any clear advantage to MethodHandle > with bind for partial application (but maybe I'm just missing something) > -- -- Howard. From howard.lovatt at gmail.com Sun May 23 17:52:26 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 24 May 2010 10:52:26 +1000 Subject: Virtual extension methods -- a strawman design Message-ID: Alex Blewitt said: > This is the classic 'diamond problem' that is experienced with multiple implementation inheritance. > Unfortunately, the proposal document (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) > brushes this under the covers (5.1) with a 'should throw an exception' at this point. This is > pretty silent, outside of any compiler warnings, and is definitely a change of behaviour. Section 4.2 seems to cover what happens. "4.2. Resolving ambiguity If the class implements multiple extended interfaces, both of which provide a default implementation for the same method name and signature, the implementing class MUST provide an implementation. (This is expected to be a quite unusual case.) The existence of the InterfaceName.super.methodName() syntax makes it easy for the class to choose one of the defaults. (We might choose to relax this restriction if both interfaces provide the same default.)" This solution is the normal solution for traits, i.e. programmer has to resolve the issues. Alex Blewitt said: > public class A implements DataStructure { > public boolean filter(FilterSam filter) {...} > } > // Later, someone makes the change: > public interface DataStructure { > extension DataStructure filter(FilterSam filter) default Default.filter; > } When A is net recompiled there is a compiler error. If A is not recompiled there is a link error. See section: "5.1. Resolving ambiguity In the unlikely case that the VM attempts to load a class that implements multiple extended interfaces that have a common defender method but with different defaults, the VM should not attempt to resolve the ambiguity automatically. Instead, it should generate a bridge method that throws UOE or similar exception. We expect this situation to be rare." I would agree with the assessment that this will be rare and therefore catching the error is sufficient. -- Howard. From neal at gafter.com Sun May 23 22:01:58 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 23 May 2010 22:01:58 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: Both default behaviors can be improved by recognizing that these different methods don't have to resolve to the same implementation: If both interface A and interface B declare defender methods with the same signature, there is no ambiguity in a class C that extends A and B. Invoking the method through C is a compile-time error (ambiguous), invoking through A gets A's behavior, and invoking through B gets B's behavior. There is no need to guess how rare these cases might be. On Sun, May 23, 2010 at 5:52 PM, Howard Lovatt wrote: > Alex Blewitt said: > >> This is the classic 'diamond problem' that is experienced with multiple implementation inheritance. >> Unfortunately, the proposal document (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) >> brushes this under the covers (5.1) with a 'should throw an exception' at this point. This is >> pretty silent, outside of any compiler warnings, and is definitely a change of behaviour. > > Section 4.2 seems to cover what happens. > > "4.2. Resolving ambiguity > If the class implements multiple extended interfaces, both of which > provide a default > implementation for the same method name and signature, the > implementing class MUST > provide an implementation. ?(This is expected to be a quite unusual > case.) ?The existence > of the InterfaceName.super.methodName() syntax makes it easy for the > class to choose > one of the defaults. ?(We might choose to relax this restriction if > both interfaces provide the same default.)" > > This solution is the normal solution for traits, i.e. programmer has > to resolve the issues. > > Alex Blewitt said: > >> public class A implements DataStructure { >> ? public boolean filter(FilterSam filter) {...} >> } >> // Later, someone makes the change: >> public interface DataStructure { >> ? extension DataStructure filter(FilterSam filter) default Default.filter; >> } > > When A is net recompiled there is a compiler error. If A is not > recompiled there is a link error. See section: > > "5.1. Resolving ambiguity > In the unlikely case that the VM attempts to load a class that > implements multiple > extended interfaces that have a common defender method but with > different defaults, the > VM should not attempt to resolve the ambiguity automatically. > Instead, it should > generate a bridge method that throws UOE or similar exception. ?We > expect this situation > to be rare." > > I would agree with the assessment that this will be rare and therefore > catching the error is sufficient. > > ?-- Howard. > > From neal at gafter.com Sun May 23 22:05:06 2010 From: neal at gafter.com (Neal Gafter) Date: Sun, 23 May 2010 22:05:06 -0700 Subject: First draft of translation document In-Reply-To: References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> <4BF57354.4000902@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> <4BF574D8.90307@oracle.com> Message-ID: On Sun, May 23, 2010 at 5:30 PM, Howard Lovatt wrote: > An interesting idea would be to change the semantics of an *anonymous* > inner class so that they could be garbage collected without having to > have first collected their class loader. Since an anonymous inner > class can only have one instance this change won't break ordinary > code. Howard: Anonymous inner classes may have many instances. From howard.lovatt at gmail.com Mon May 24 00:42:53 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 24 May 2010 17:42:53 +1000 Subject: First draft of translation document In-Reply-To: References: <7FDA6630E1822F448C97A48D5D73309474E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BF55612.30508@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E6EE@EXVMSTOR302.intra.rakuten.co.jp> <4BF57354.4000902@oracle.com> <7FDA6630E1822F448C97A48D5D73309474E714@EXVMSTOR302.intra.rakuten.co.jp> <4BF574D8.90307@oracle.com> Message-ID: Yes, thanks for the correction. I meant to say that anonymous inner classes can only have one *point of creation* (not one instance). On 24 May 2010 15:05, Neal Gafter wrote: > On Sun, May 23, 2010 at 5:30 PM, Howard Lovatt wrote: >> An interesting idea would be to change the semantics of an *anonymous* >> inner class so that they could be garbage collected without having to >> have first collected their class loader. Since an anonymous inner >> class can only have one instance this change won't break ordinary >> code. > > Howard: Anonymous inner classes may have many instances. > -- -- Howard. From howard.lovatt at gmail.com Mon May 24 01:06:02 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Mon, 24 May 2010 18:06:02 +1000 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: Just to clarify my reading of the spec: If we initially have: interface IA {} interface IB {} class A implements IA {} class B implements IB {} class AB implements IA, IB {} Then modify: interface IA { extension int m() default IAs.m; } interface IB { extension int m() default IBs.m; } And we don't recompile the classes A, B, and AB then A and B will work just fine and as expected, however AB will throw an exception if m is called. I think that this combination of: 1. Adding the same extension method signature to multiple interfaces 2. Not recompiling classes that implement more than one of these interfaces 3. Calling the extension method on the non re-compiled classes Will be reasonably rare, hence I thought the specification was reasonable. Another option would be for the class loading to fail for AB, since m is ambiguous. I would have thought that either AB failing to load (I suggested this for my Trait proposal) or the runtime exception proposed in the Oracle document are reasonable behaviors. On 24 May 2010 15:01, Neal Gafter wrote: > Both default behaviors can be improved by recognizing that these > different methods don't have to resolve to the same implementation: > > If both interface A and interface B declare defender methods with the > same signature, there is no ambiguity in a class C that extends A and > B. ?Invoking the method through C is a compile-time error (ambiguous), > invoking through A gets A's behavior, and invoking through B gets B's > behavior. ?There is no need to guess how rare these cases might be. > > On Sun, May 23, 2010 at 5:52 PM, Howard Lovatt wrote: >> Alex Blewitt said: >> >>> This is the classic 'diamond problem' that is experienced with multiple implementation inheritance. >>> Unfortunately, the proposal document (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) >>> brushes this under the covers (5.1) with a 'should throw an exception' at this point. This is >>> pretty silent, outside of any compiler warnings, and is definitely a change of behaviour. >> >> Section 4.2 seems to cover what happens. >> >> "4.2. Resolving ambiguity >> If the class implements multiple extended interfaces, both of which >> provide a default >> implementation for the same method name and signature, the >> implementing class MUST >> provide an implementation. ?(This is expected to be a quite unusual >> case.) ?The existence >> of the InterfaceName.super.methodName() syntax makes it easy for the >> class to choose >> one of the defaults. ?(We might choose to relax this restriction if >> both interfaces provide the same default.)" >> >> This solution is the normal solution for traits, i.e. programmer has >> to resolve the issues. >> >> Alex Blewitt said: >> >>> public class A implements DataStructure { >>> ? public boolean filter(FilterSam filter) {...} >>> } >>> // Later, someone makes the change: >>> public interface DataStructure { >>> ? extension DataStructure filter(FilterSam filter) default Default.filter; >>> } >> >> When A is net recompiled there is a compiler error. If A is not >> recompiled there is a link error. See section: >> >> "5.1. Resolving ambiguity >> In the unlikely case that the VM attempts to load a class that >> implements multiple >> extended interfaces that have a common defender method but with >> different defaults, the >> VM should not attempt to resolve the ambiguity automatically. >> Instead, it should >> generate a bridge method that throws UOE or similar exception. ?We >> expect this situation >> to be rare." >> >> I would agree with the assessment that this will be rare and therefore >> catching the error is sufficient. >> >> ?-- Howard. >> >> > -- -- Howard. From neal at gafter.com Mon May 24 06:44:13 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 24 May 2010 06:44:13 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: On Mon, May 24, 2010 at 1:06 AM, Howard Lovatt wrote: > Just to clarify my reading of the spec: > > If we initially have: > > interface IA {} > interface IB {} > class A implements IA {} > class B implements IB {} > class AB implements IA, IB {} > > Then modify: > > interface IA { extension int m() default IAs.m; } > interface IB { extension int m() default IBs.m; } > > And we don't recompile the classes A, B, and AB then A and B will work > just fine and as expected, however AB will throw an exception if m is > called. > > I think that this combination of: > > 1. Adding the same extension method signature to multiple interfaces > 2. Not recompiling classes that implement more than one of these interfaces > 3. Calling the extension method on the non re-compiled classes I would expect a compile-time ambiguity when compiling the invocation in this case. From nathan.bryant at linkshare.com Mon May 24 09:37:41 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Tue, 25 May 2010 01:37:41 +0900 Subject: Virtual extension methods -- a strawman design References: Message-ID: <7FDA6630E1822F448C97A48D5D7330947A1165@EXVMSTOR302.intra.rakuten.co.jp> Yes, and Java up to Java 6 also brushes the problem under the covers... by not even attempting to solve it at all. Fundamentally, this proposal is neither multiple inheritance nor traits. It just is what it is: extension methods. Some of the more important differences: * If this were multiple inheritance, extension methods could themselves reference "super". In this proposal, they can't, because they're just ordinary static methods. (MethodHandles from a lookupSpecial would be a way to fake that, but I digress.) * The order of implemented interfaces does not affect method resolution, as it does for both multiple inheritance and traits. * As in multiple inheritance, but unlike with traits, "super" is always resolved statically. * In some implementations of traits, when a trait gains or loses a member, classes that inherit from it must be recompiled without exception; it's clear that any implementation with such limitations would not meet the requirements for this project. That limitation is not the case here; the brittleness limitations being proposed here are more limited. So from the perspective of the principle of least surprise, this implementation should be easier to understand for novice programmers compared to either multiple inheritance or traits. The proposal is useful for what it's designed for: widening primitive interfaces. It doesn't seem particularly useful for stacking modifications. -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Howard Lovatt Sent: Sunday, May 23, 2010 8:52 PM To: lambda-dev at openjdk.java.net Subject: RE: Virtual extension methods -- a strawman design Alex Blewitt said: > This is the classic 'diamond problem' that is experienced with multiple implementation inheritance. > Unfortunately, the proposal document (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) > brushes this under the covers (5.1) with a 'should throw an exception' at this point. This is > pretty silent, outside of any compiler warnings, and is definitely a change of behaviour. Section 4.2 seems to cover what happens. "4.2. Resolving ambiguity If the class implements multiple extended interfaces, both of which provide a default implementation for the same method name and signature, the implementing class MUST provide an implementation. (This is expected to be a quite unusual case.) The existence of the InterfaceName.super.methodName() syntax makes it easy for the class to choose one of the defaults. (We might choose to relax this restriction if both interfaces provide the same default.)" This solution is the normal solution for traits, i.e. programmer has to resolve the issues. Alex Blewitt said: > public class A implements DataStructure { > public boolean filter(FilterSam filter) {...} > } > // Later, someone makes the change: > public interface DataStructure { > extension DataStructure filter(FilterSam filter) default Default.filter; > } When A is net recompiled there is a compiler error. If A is not recompiled there is a link error. See section: "5.1. Resolving ambiguity In the unlikely case that the VM attempts to load a class that implements multiple extended interfaces that have a common defender method but with different defaults, the VM should not attempt to resolve the ambiguity automatically. Instead, it should generate a bridge method that throws UOE or similar exception. We expect this situation to be rare." I would agree with the assessment that this will be rare and therefore catching the error is sufficient. -- Howard. From howard.lovatt at gmail.com Mon May 24 15:48:10 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 25 May 2010 08:48:10 +1000 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: If you recompile AB then you get an error. If you don't recompile AB and call m then you get an Exception. As I said, this is reasonable behaviour and so is a load error, i.e. either option fine by me. On Monday, May 24, 2010, Neal Gafter wrote: > On Mon, May 24, 2010 at 1:06 AM, Howard Lovatt wrote: >> Just to clarify my reading of the spec: >> >> If we initially have: >> >> interface IA {} >> interface IB {} >> class A implements IA {} >> class B implements IB {} >> class AB implements IA, IB {} >> >> Then modify: >> >> interface IA { extension int m() default IAs.m; } >> interface IB { extension int m() default IBs.m; } >> >> And we don't recompile the classes A, B, and AB then A and B will work >> just fine and as expected, however AB will throw an exception if m is >> called. >> >> I think that this combination of: >> >> 1. Adding the same extension method signature to multiple interfaces >> 2. Not recompiling classes that implement more than one of these interfaces >> 3. Calling the extension method on the non re-compiled classes > > I would expect a compile-time ambiguity when compiling the invocation > in this case. > -- -- Howard. From howard.lovatt at gmail.com Mon May 24 16:08:51 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 25 May 2010 09:08:51 +1000 Subject: Virtual extension methods -- a strawman design In-Reply-To: <7FDA6630E1822F448C97A48D5D7330947A1165@EXVMSTOR302.intra.rakuten.co.jp> References: <7FDA6630E1822F448C97A48D5D7330947A1165@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: Comments inline On Tuesday, May 25, 2010, Nathan Bryant wrote: > Yes, and Java up to Java 6 also brushes the problem under the covers... > by not even attempting to solve it at all. > > Fundamentally, this proposal is neither multiple inheritance nor traits. > It just is what it is: extension methods. > > Some of the more important differences: > > * If this were multiple inheritance, extension methods could themselves > reference "super". In this proposal, they can't, because they're just > ordinary static methods. (MethodHandles from a lookupSpecial would be a > way to fake that, but I digress.) Yes, and you could with traits also. With traits you can usually call any of the supers. With MI and mixins just the immediate super. Since the extension methods call static methods you can always call these directly (though not quite as robust in the face of change). On the plus side calling a static method is very flexible, e.g. a static method getFirst( List ) could be added to List as getFirst and to Stack as pop (i.e. very good code reuse and support for method renaming). > * The order of implemented interfaces does not affect method resolution, > as it does for both multiple inheritance and traits. Not normally with traits, but it does with Scala traits that are some sort of cross between traits and mixins. > * As in multiple inheritance, but unlike with traits, "super" is always > resolved statically. Normally statically resolved with traits (but not Scala) > * In some implementations of traits, when a trait gains or loses a > member, classes that inherit from it must be recompiled without > exception; it's clear that any implementation with such limitations > would not meet the requirements for this project. That limitation is not > the case here; the brittleness limitations being proposed here are more > limited. I thought they struck a good compromise that allows for traits to be modified without too many problems. > So from the perspective of the principle of least surprise, this > implementation should be easier to understand for novice programmers > compared to either multiple inheritance or traits. > > The proposal is useful for what it's designed for: widening primitive > interfaces. It doesn't seem particularly useful for stacking > modifications. > > > > -----Original Message----- > From: lambda-dev-bounces at openjdk.java.net > [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of Howard Lovatt > Sent: Sunday, May 23, 2010 8:52 PM > To: lambda-dev at openjdk.java.net > Subject: RE: Virtual extension methods -- a strawman design > > Alex Blewitt said: > >> This is the classic 'diamond problem' that is experienced with > multiple implementation inheritance. >> Unfortunately, the proposal document > (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) >> brushes this under the covers (5.1) with a 'should throw an exception' > at this point. This is >> pretty silent, outside of any compiler warnings, and is definitely a > change of behaviour. > > Section 4.2 seems to cover what happens. > > "4.2. Resolving ambiguity > If the class implements multiple extended interfaces, both of which > provide a default > implementation for the same method name and signature, the > implementing class MUST > provide an implementation. ?(This is expected to be a quite unusual > case.) ?The existence > of the InterfaceName.super.methodName() syntax makes it easy for the > class to choose > one of the defaults. ?(We might choose to relax this restriction if > both interfaces provide the same default.)" > > This solution is the normal solution for traits, i.e. programmer has > to resolve the issues. > > Alex Blewitt said: > >> public class A implements DataStructure { >> ? public boolean filter(FilterSam filter) {...} >> } >> // Later, someone makes the change: >> public interface DataStructure { >> ? extension DataStructure filter(FilterSam filter) default > Default.filter; >> } > > When A is net recompiled there is a compiler error. If A is not > recompiled there is a link error. See section: > > "5.1. Resolving ambiguity > In the unlikely case that the VM attempts to load a class that > implements multiple > extended interfaces that have a common defender method but with > different defaults, the > VM should not attempt to resolve the ambiguity automatically. > Instead, it should > generate a bridge method that throws UOE or similar exception. ?We > expect this situation > to be rare." > > I would agree with the assessment that this will be rare and therefore > catching the error is sufficient. > > ?-- Howard. > > -- -- Howard. From nathan.bryant at linkshare.com Mon May 24 16:20:19 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Tue, 25 May 2010 08:20:19 +0900 Subject: Virtual extension methods -- a strawman design References: <7FDA6630E1822F448C97A48D5D7330947A1165@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: <7FDA6630E1822F448C97A48D5D7330947A1530@EXVMSTOR302.intra.rakuten.co.jp> Indeed, could be usable by scalac to make its own traits less brittle (?) -----Original Message----- From: Howard Lovatt [mailto:howard.lovatt at gmail.com] >I thought they struck a good compromise that allows for traits to be >modified without too many problems. From neal at gafter.com Mon May 24 18:09:14 2010 From: neal at gafter.com (Neal Gafter) Date: Mon, 24 May 2010 18:09:14 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: On Mon, May 24, 2010 at 3:48 PM, Howard Lovatt wrote: > If you recompile AB then you get an error. If you don't recompile AB > and call m then you get an Exception. As I said, this is reasonable > behaviour and so is a load error, i.e. either option fine by me. > If you don't recompile AB, then AB contains no invocation of m. So there is no error. From howard.lovatt at gmail.com Mon May 24 19:08:19 2010 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Tue, 25 May 2010 12:08:19 +1000 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: The loader adds m when the class loads, therefore it exists. If m is ambiguous the added method throws an exception. On Tuesday, May 25, 2010, Neal Gafter wrote: > On Mon, May 24, 2010 at 3:48 PM, Howard Lovatt wrote: > > > > If you recompile AB then you get an error. If you don't recompile AB > and call m then you get an Exception. As I said, this is reasonable > behaviour and so is a load error, i.e. either option fine by me. > > If you don't recompile AB, then AB contains no invocation of m.? So there is no error. > > -- -- Howard. From fweimer at bfk.de Tue May 25 05:40:53 2010 From: fweimer at bfk.de (Florian Weimer) Date: Tue, 25 May 2010 12:40:53 +0000 Subject: Virtual extension methods -- a strawman design In-Reply-To: <4BEDD9E9.7050300@oracle.com> (Brian Goetz's message of "Fri\, 14 May 2010 19\:16\:57 -0400") References: <4BEDD9E9.7050300@oracle.com> Message-ID: <82632cjgru.fsf@mid.bfk.de> * Brian Goetz: > The attached document reflects our current thinking in the area of > extension methods, which was introduced in section 8 of the Strawman > proposal. This document (arguably) improves on the static extension > method scheme presented there. The document is written in a way that gives the impression that extension methods are to be used by the JDK 7 platform authors only. Is this really your intent? The reason I'm wondering is the final sentence in the first paragraph of section 4 ("The class file emitted by the compiler implements all methods in the interface...") and the first sentence in section 5 ("Classes compiled by the JDK 7 compiler will not need any special treatment"). This is just not true if the feature (that is, binary-compatible evolution of interfaces) is available to the general public. Are there any constraints on the visibility of the default method? The obviously loophole-free approach would be to require that they are public methods in the same package as the interface itself. If you permit non-public methods here (or public methods in other packages), you need to make sure that class authors are aware of the ability to reference overridden methods way above in the class hierarchy, which might be used to bypass security checks. -- Florian Weimer BFK edv-consulting GmbH http://www.bfk.de/ Kriegsstra?e 100 tel: +49-721-96201-1 D-76133 Karlsruhe fax: +49-721-96201-99 From reinier at zwitserloot.com Tue May 25 10:15:11 2010 From: reinier at zwitserloot.com (Reinier Zwitserloot) Date: Tue, 25 May 2010 19:15:11 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BF14B8F.1090206@oracle.com> <4BF14F2E.5010701@univ-mlv.fr> Message-ID: Alex, replies inline. --Reinier Zwitserloot On Sun, May 23, 2010 at 5:03 PM, Alex Blewitt wrote: > > However, I have concerns with the defender methods in more general terms. > Putting an alias to a static method is akin to permitting code in an > interface; what happens in the following case: > > [SNIP: Diamond problem] I thought the spec was pretty clear. If compiling the leaf of a diamond situation (class AB implements A, B), then javac will refuse to generate a class file and will instead error out with a message stating something along the lines of: "method stuff() has default implementations in both A and B. Resolve this ambiguity by writing your own stuff() method." If the JVM runtime environment consists of mixed classes, then the diamond problem can still occur without anyone getting a compiler error. In this case, the usual thing happens when you run a JVM environment with mixed classes: Errors. I don't see why this proposal needs to be held to a higher standard here. The key point is that errors _do_ occur, which is a lot better than silently picking one of the multiple available default implementations (better because by picking one, order becomes relevant, and that's bad). As was mentioned in the spec, the compiler will automatically insert an implementation of the stuff() method in any class implementing either A or B (or both), wrapping the call to the provided default. This mechanism can detect the diamond situation just as easily, and can then generate a method that will throw an exception, in keeping with how the JVM behaves with interfaces in general (no load errors, instead you get some sort of throwable when you call a method). All that needs to be ensured is that the situations where such a diamond situation would indeed occur is rare (and it is trivial to see that it will be). I would agree with you that the situation would have to be excluded entirely if the JVM would have to resort to ambiguous behaviour when it happens, but that's not the case here. > > Even without that, I don't see that any consideration has been given to > what happens to already existing methods which are used prior to this > change. For example, consider the lowly 'filter' method - some > implementations may perform an in-place filter, returning 'true' or 'false' > to indicate if any changes were allowed, whereas others may return a new > copy of the data structure with elements that match the filter. What if a > generic 'filter' method is then defaulted to the interface? > > Again a problem java already suffers from. You can add filter() to List right now and it'll cause one of two things to happen if some list implementation already has a filter method: (1) The signature matches _exactly_. In this case, the filter() of the ListImpl will override the interface's filter method. Awkward situation if ListImpl's filter has different semantics from those explained in List's filter(). (2) The signatures do not match _exactly_. In this case, the filter() of the ListImpl doesn't override anything, and the usual thing happens: NoSuchMethodError. If (re)compiling ListImpl, you'll get a warning on filter() due to a missing @Override, presuming you've got your build system set up properly. There's a convoluted way out of this, but I doubt it's worth it. From javac7 and up, *ALL* methods are compiled with an extended field in the class file listing all methods it was meant to override (this field is still present if you're not overriding anything). When doing virtual lookup, methods are ignored if there is no chain towards the target method in this extended field. If the field is missing (compiled with javac6 or less), for backwards compatibility reasons, the method is presumed to override everything. Now we have a situation where previously there was no common filter() > signature, there is now. The problem is that class A may well have been > written long before the existence of B, but we have now introduced a > situation where client code invoking A.filter() is presented with the return > value of a different type to which it expects. > > That won't happen. Unless a signature matches _exactly_ it's not the same method. Therefore anyone invoking any method will always get back a value of exactly the type they were expecting. > The key problem is that the draft spec has no observations of what should > happen when the extension method is of a different signature (i.e. not > covariant in the return types). > > As it was primarily focused on the JVM/class file, there was no need. You can't have overriding of methods if signatures are different. Even covariant return types don't exist at the JVM level; javac instead generates a bridge method. At the javac level, this situation can be detected, and an error can be produced. From brian.goetz at oracle.com Tue May 25 10:42:12 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 25 May 2010 13:42:12 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: <4BEDD9E9.7050300@oracle.com> <4BF14B8F.1090206@oracle.com> <4BF14F2E.5010701@univ-mlv.fr> Message-ID: <4BFC0BF4.9040005@oracle.com> > Alex, replies inline. > > --Reinier Zwitserloot Reinier is spot-on here, I just want to amplify one point: > The key point is that errors _do_ occur, which is a lot > better than silently picking one of the multiple available default > implementations (better because by picking one, order becomes relevant, and > that's bad). Even if we wanted to do this (and it was considered), we couldn't: the relationship between the order of interfaces in a source file and the order in which they appear in the class file is unspecified. From brian.goetz at oracle.com Tue May 25 10:59:24 2010 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 25 May 2010 13:59:24 -0400 Subject: Virtual extension methods -- a strawman design In-Reply-To: <82632cjgru.fsf@mid.bfk.de> References: <4BEDD9E9.7050300@oracle.com> <82632cjgru.fsf@mid.bfk.de> Message-ID: <4BFC0FFC.2080807@oracle.com> >> The attached document reflects our current thinking in the area of >> extension methods, which was introduced in section 8 of the Strawman >> proposal. This document (arguably) improves on the static extension >> method scheme presented there. > > The document is written in a way that gives the impression that > extension methods are to be used by the JDK 7 platform authors only. > Is this really your intent? No, but I could see how it could come across that way. The intention is that this is a mechanism for *library owners* to evolve their already-published libraries. Oracle is certainly an important member of the category of library owners, but not the only one. > The reason I'm wondering is the final sentence in the first paragraph > of section 4 ("The class file emitted by the compiler implements all > methods in the interface...") and the first sentence in section 5 > ("Classes compiled by the JDK 7 compiler will not need any special > treatment"). This is just not true if the feature (that is, > binary-compatible evolution of interfaces) is available to the general > public. Yes, that statement in the document was optimistically incorrect. > Are there any constraints on the visibility of the default method? > The obviously loophole-free approach would be to require that they are > public methods in the same package as the interface itself. If you > permit non-public methods here (or public methods in other packages), > you need to make sure that class authors are aware of the ability to > reference overridden methods way above in the class hierarchy, which > might be used to bypass security checks. That's definitely on the "niggly details that need some thought" list. As you say, public would make everything easy. From peter.levart at gmail.com Tue May 25 11:35:10 2010 From: peter.levart at gmail.com (Peter Levart) Date: Tue, 25 May 2010 20:35:10 +0200 Subject: Virtual extension methods -- a strawman design In-Reply-To: References: Message-ID: <201005252035.10944.peter.levart@gmail.com> On Monday 24 May 2010 07:01:58 am Neal Gafter wrote: > Both default behaviors can be improved by recognizing that these > different methods don't have to resolve to the same implementation: > > If both interface A and interface B declare defender methods with the > same signature, there is no ambiguity in a class C that extends A and > B. Invoking the method through C is a compile-time error (ambiguous), > invoking through A gets A's behavior, and invoking through B gets B's > behavior. There is no need to guess how rare these cases might be. > How could this be achieved without modifying the specification of the JVM? If C implements both A and B then it only contains a single instance method that @Override-s both methods in interfaces A and B at the same time. The invokeinterface bytecode dispatches to the same method implementation regardless of whether it was specified as A.method or B.method. How could C provide distinct implementations of a method with the same name and parameter types that would be selected in response to invoking them via interface A or B? Is it possible for code emited by javac in the single method body to find out via which invokeinterface method it was actually invoked and dispatch accordingly? Regards, Peter > On Sun, May 23, 2010 at 5:52 PM, Howard Lovatt wrote: > > Alex Blewitt said: > >> This is the classic 'diamond problem' that is experienced with multiple > >> implementation inheritance. Unfortunately, the proposal document > >> (http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf) brushes this > >> under the covers (5.1) with a 'should throw an exception' at this > >> point. This is pretty silent, outside of any compiler warnings, and is > >> definitely a change of behaviour. > > > > Section 4.2 seems to cover what happens. > > > > "4.2. Resolving ambiguity > > If the class implements multiple extended interfaces, both of which > > provide a default > > implementation for the same method name and signature, the > > implementing class MUST > > provide an implementation. (This is expected to be a quite unusual > > case.) The existence > > of the InterfaceName.super.methodName() syntax makes it easy for the > > class to choose > > one of the defaults. (We might choose to relax this restriction if > > both interfaces provide the same default.)" > > > > This solution is the normal solution for traits, i.e. programmer has > > to resolve the issues. > > > > Alex Blewitt said: > >> public class A implements DataStructure { > >> public boolean filter(FilterSam filter) {...} > >> } > >> // Later, someone makes the change: > >> public interface DataStructure { > >> extension DataStructure filter(FilterSam filter) default > >> Default.filter; } > > > > When A is net recompiled there is a compiler error. If A is not > > recompiled there is a link error. See section: > > > > "5.1. Resolving ambiguity > > In the unlikely case that the VM attempts to load a class that > > implements multiple > > extended interfaces that have a common defender method but with > > different defaults, the > > VM should not attempt to resolve the ambiguity automatically. > > Instead, it should > > generate a bridge method that throws UOE or similar exception. We > > expect this situation > > to be rare." > > > > I would agree with the assessment that this will be rare and therefore > > catching the error is sufficient. > > > > -- Howard. From neal at gafter.com Tue May 25 14:29:11 2010 From: neal at gafter.com (Neal Gafter) Date: Tue, 25 May 2010 14:29:11 -0700 Subject: Virtual extension methods -- a strawman design In-Reply-To: <201005252035.10944.peter.levart@gmail.com> References: <201005252035.10944.peter.levart@gmail.com> Message-ID: On Tue, May 25, 2010 at 11:35 AM, Peter Levart wrote: > On Monday 24 May 2010 07:01:58 am Neal Gafter wrote: > > Both default behaviors can be improved by recognizing that these > > different methods don't have to resolve to the same implementation: > > > > If both interface A and interface B declare defender methods with the > > same signature, there is no ambiguity in a class C that extends A and > > B. Invoking the method through C is a compile-time error (ambiguous), > > invoking through A gets A's behavior, and invoking through B gets B's > > behavior. There is no need to guess how rare these cases might be. > > > > How could this be achieved without modifying the specification of the JVM? Adding extension methods as contemplated requires changing the JVM specification. > How could C provide distinct implementations of a method with the same name > and parameter types > that would be selected in response to invoking them via interface A or B? Doing that would require additional language support. If it is deemed worth doing there is an obvious syntax to use. > Is it possible for > code emited by javac in the single method body to find out via which > invokeinterface method it > was actually invoked and dispatch accordingly? > I don't propose such a thing. From maurizio.cimadamore at oracle.com Thu May 27 10:33:09 2010 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Thu, 27 May 2010 17:33:09 +0000 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: Message-ID: <20100527173313.6763646E4A@hg.openjdk.java.net> Changeset: 7704dcd17e0b Author: mcimadamore Date: 2010-05-27 18:11 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b initial lambda push; the current prototype suuports the following features: *) function types syntax (optionally enabled with -XDallowFunctionTypes) *) function types subtyping *) full support for lambda expression of type 1 and 2 *) inference of thrown types/return type in a lambda *) lambda conversion using rules specified in v0.1.5 draft *) support references to 'this' (both explicit and implicit) *) translation using method handles The modified script build of the langtools repository now generates an additional jarfile called javacrt.jar which contains an helper class to be used during SAM conversion; after the build, the generated scripts javac/java will take care of automatically setting up the required dependencies so that code containing lambda expressions can be compiled and executed. ! make/build.properties ! make/build.xml + src/share/bin/java.sh-template ! src/share/bin/launcher.sh-template + src/share/classes/com/sun/runtime/ProxyHelper.java + src/share/classes/com/sun/source/tree/FunctionTypeTree.java + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java ! src/share/classes/com/sun/source/tree/Tree.java ! src/share/classes/com/sun/source/tree/TreeVisitor.java ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java ! src/share/classes/com/sun/source/util/TreeScanner.java ! src/share/classes/com/sun/tools/javac/code/Flags.java ! src/share/classes/com/sun/tools/javac/code/Printer.java ! src/share/classes/com/sun/tools/javac/code/Scope.java ! src/share/classes/com/sun/tools/javac/code/Source.java ! src/share/classes/com/sun/tools/javac/code/Symtab.java ! src/share/classes/com/sun/tools/javac/code/Type.java ! src/share/classes/com/sun/tools/javac/code/Types.java ! src/share/classes/com/sun/tools/javac/comp/Attr.java ! src/share/classes/com/sun/tools/javac/comp/Check.java ! src/share/classes/com/sun/tools/javac/comp/Flow.java ! src/share/classes/com/sun/tools/javac/comp/Lower.java ! src/share/classes/com/sun/tools/javac/comp/Resolve.java ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java ! src/share/classes/com/sun/tools/javac/parser/Scanner.java ! src/share/classes/com/sun/tools/javac/parser/Token.java ! src/share/classes/com/sun/tools/javac/resources/compiler.properties ! src/share/classes/com/sun/tools/javac/tree/JCTree.java ! src/share/classes/com/sun/tools/javac/tree/Pretty.java ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java ! src/share/classes/com/sun/tools/javac/util/Names.java ! src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java + test/tools/javac/lambda/LambdaCapture01.java + test/tools/javac/lambda/LambdaConv01.java + test/tools/javac/lambda/LambdaExpr01.java + test/tools/javac/lambda/LambdaExpr02.java + test/tools/javac/lambda/LambdaScope01.java + test/tools/javac/lambda/NakedThis.java + test/tools/javac/lambda/NakedThis.out From nathan.bryant at linkshare.com Thu May 27 10:45:52 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Fri, 28 May 2010 02:45:52 +0900 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: References: <20100527173313.6763646E4A@hg.openjdk.java.net> Message-ID: <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> This is great! But what is the syntax? -----Original Message----- From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of maurizio.cimadamore at oracle.com Sent: Thursday, May 27, 2010 1:33 PM To: lambda-dev at openjdk.java.net Subject: hg: lambda/lambda/langtools: initial lambda push;the current prototype suuports the following features: Changeset: 7704dcd17e0b Author: mcimadamore Date: 2010-05-27 18:11 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b initial lambda push; the current prototype suuports the following features: *) function types syntax (optionally enabled with -XDallowFunctionTypes) *) function types subtyping *) full support for lambda expression of type 1 and 2 *) inference of thrown types/return type in a lambda *) lambda conversion using rules specified in v0.1.5 draft *) support references to 'this' (both explicit and implicit) *) translation using method handles The modified script build of the langtools repository now generates an additional jarfile called javacrt.jar which contains an helper class to be used during SAM conversion; after the build, the generated scripts javac/java will take care of automatically setting up the required dependencies so that code containing lambda expressions can be compiled and executed. ! make/build.properties ! make/build.xml + src/share/bin/java.sh-template ! src/share/bin/launcher.sh-template + src/share/classes/com/sun/runtime/ProxyHelper.java + src/share/classes/com/sun/source/tree/FunctionTypeTree.java + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java ! src/share/classes/com/sun/source/tree/Tree.java ! src/share/classes/com/sun/source/tree/TreeVisitor.java ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java ! src/share/classes/com/sun/source/util/TreeScanner.java ! src/share/classes/com/sun/tools/javac/code/Flags.java ! src/share/classes/com/sun/tools/javac/code/Printer.java ! src/share/classes/com/sun/tools/javac/code/Scope.java ! src/share/classes/com/sun/tools/javac/code/Source.java ! src/share/classes/com/sun/tools/javac/code/Symtab.java ! src/share/classes/com/sun/tools/javac/code/Type.java ! src/share/classes/com/sun/tools/javac/code/Types.java ! src/share/classes/com/sun/tools/javac/comp/Attr.java ! src/share/classes/com/sun/tools/javac/comp/Check.java ! src/share/classes/com/sun/tools/javac/comp/Flow.java ! src/share/classes/com/sun/tools/javac/comp/Lower.java ! src/share/classes/com/sun/tools/javac/comp/Resolve.java ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java ! src/share/classes/com/sun/tools/javac/parser/Scanner.java ! src/share/classes/com/sun/tools/javac/parser/Token.java ! src/share/classes/com/sun/tools/javac/resources/compiler.properties ! src/share/classes/com/sun/tools/javac/tree/JCTree.java ! src/share/classes/com/sun/tools/javac/tree/Pretty.java ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java ! src/share/classes/com/sun/tools/javac/util/Names.java ! src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java + test/tools/javac/lambda/LambdaCapture01.java + test/tools/javac/lambda/LambdaConv01.java + test/tools/javac/lambda/LambdaExpr01.java + test/tools/javac/lambda/LambdaExpr02.java + test/tools/javac/lambda/LambdaScope01.java + test/tools/javac/lambda/NakedThis.java + test/tools/javac/lambda/NakedThis.out From jkuhnert at gmail.com Thu May 27 10:59:16 2010 From: jkuhnert at gmail.com (Jesse Kuhnert) Date: Thu, 27 May 2010 13:59:16 -0400 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <20100527173313.6763646E4A@hg.openjdk.java.net> References: <20100527173313.6763646E4A@hg.openjdk.java.net> Message-ID: You guys kick ass. =) On Thu, May 27, 2010 at 1:33 PM, wrote: > Changeset: 7704dcd17e0b > Author: ? ?mcimadamore > Date: ? ? ?2010-05-27 18:11 +0100 > URL: ? ? ? http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b > > initial lambda push; the current prototype suuports the following features: > *) function types syntax (optionally enabled with -XDallowFunctionTypes) > *) function types subtyping > *) full support for lambda expression of type 1 and 2 > *) inference of thrown types/return type in a lambda > *) lambda conversion using rules specified in v0.1.5 draft > *) support references to 'this' (both explicit and implicit) > *) translation using method handles > > The modified script build of the langtools repository now generates an additional jarfile called javacrt.jar which contains an helper class to be used during SAM conversion; after the build, the generated scripts javac/java will take care of automatically setting up the required dependencies so that code containing lambda expressions can be compiled and executed. > > ! make/build.properties > ! make/build.xml > + src/share/bin/java.sh-template > ! src/share/bin/launcher.sh-template > + src/share/classes/com/sun/runtime/ProxyHelper.java > + src/share/classes/com/sun/source/tree/FunctionTypeTree.java > + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java > ! src/share/classes/com/sun/source/tree/Tree.java > ! src/share/classes/com/sun/source/tree/TreeVisitor.java > ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java > ! src/share/classes/com/sun/source/util/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/code/Flags.java > ! src/share/classes/com/sun/tools/javac/code/Printer.java > ! src/share/classes/com/sun/tools/javac/code/Scope.java > ! src/share/classes/com/sun/tools/javac/code/Source.java > ! src/share/classes/com/sun/tools/javac/code/Symtab.java > ! src/share/classes/com/sun/tools/javac/code/Type.java > ! src/share/classes/com/sun/tools/javac/code/Types.java > ! src/share/classes/com/sun/tools/javac/comp/Attr.java > ! src/share/classes/com/sun/tools/javac/comp/Check.java > ! src/share/classes/com/sun/tools/javac/comp/Flow.java > ! src/share/classes/com/sun/tools/javac/comp/Lower.java > ! src/share/classes/com/sun/tools/javac/comp/Resolve.java > ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java > ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java > ! src/share/classes/com/sun/tools/javac/parser/Scanner.java > ! src/share/classes/com/sun/tools/javac/parser/Token.java > ! src/share/classes/com/sun/tools/javac/resources/compiler.properties > ! src/share/classes/com/sun/tools/javac/tree/JCTree.java > ! src/share/classes/com/sun/tools/javac/tree/Pretty.java > ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java > ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java > ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java > ! src/share/classes/com/sun/tools/javac/util/Names.java > ! src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java > + test/tools/javac/lambda/LambdaCapture01.java > + test/tools/javac/lambda/LambdaConv01.java > + test/tools/javac/lambda/LambdaExpr01.java > + test/tools/javac/lambda/LambdaExpr02.java > + test/tools/javac/lambda/LambdaScope01.java > + test/tools/javac/lambda/NakedThis.java > + test/tools/javac/lambda/NakedThis.out > > > From alessiostalla at gmail.com Thu May 27 11:11:13 2010 From: alessiostalla at gmail.com (Alessio Stalla) Date: Thu, 27 May 2010 20:11:13 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: On Thu, May 27, 2010 at 7:45 PM, Nathan Bryant wrote: > This is great! But what is the syntax? You can see an example of it at http://hg.openjdk.java.net/lambda/lambda/langtools/file/7704dcd17e0b/test/tools/javac/lambda/LambdaCapture01.java (and in general examining the tests that they have committed). From maurizio.cimadamore at oracle.com Thu May 27 12:47:21 2010 From: maurizio.cimadamore at oracle.com (maurizio cimadamore) Date: Thu, 27 May 2010 20:47:21 +0100 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> Message-ID: <4BFECC49.2040101@oracle.com> Hi The prototype supports the syntax described in the strawman proposal [1]. You might want to look at some of the regression tests, in particular LambdaExpr01/LambdaExpr02 [2,3] to get an idea of what the syntax look like. Thanks Maurizio [1] http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt [2] http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr01.java [3] http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr02.java On 27/05/10 18:45, Nathan Bryant wrote: > This is great! But what is the syntax? > > -----Original Message----- > From: lambda-dev-bounces at openjdk.java.net > [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of > maurizio.cimadamore at oracle.com > Sent: Thursday, May 27, 2010 1:33 PM > To: lambda-dev at openjdk.java.net > Subject: hg: lambda/lambda/langtools: initial lambda push;the current > prototype suuports the following features: > > Changeset: 7704dcd17e0b > Author: mcimadamore > Date: 2010-05-27 18:11 +0100 > URL: > http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b > > initial lambda push; the current prototype suuports the following > features: > *) function types syntax (optionally enabled with -XDallowFunctionTypes) > *) function types subtyping > *) full support for lambda expression of type 1 and 2 > *) inference of thrown types/return type in a lambda > *) lambda conversion using rules specified in v0.1.5 draft > *) support references to 'this' (both explicit and implicit) > *) translation using method handles > > The modified script build of the langtools repository now generates an > additional jarfile called javacrt.jar which contains an helper class to > be used during SAM conversion; after the build, the generated scripts > javac/java will take care of automatically setting up the required > dependencies so that code containing lambda expressions can be compiled > and executed. > > ! make/build.properties > ! make/build.xml > + src/share/bin/java.sh-template > ! src/share/bin/launcher.sh-template > + src/share/classes/com/sun/runtime/ProxyHelper.java > + src/share/classes/com/sun/source/tree/FunctionTypeTree.java > + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java > ! src/share/classes/com/sun/source/tree/Tree.java > ! src/share/classes/com/sun/source/tree/TreeVisitor.java > ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java > ! src/share/classes/com/sun/source/util/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/code/Flags.java > ! src/share/classes/com/sun/tools/javac/code/Printer.java > ! src/share/classes/com/sun/tools/javac/code/Scope.java > ! src/share/classes/com/sun/tools/javac/code/Source.java > ! src/share/classes/com/sun/tools/javac/code/Symtab.java > ! src/share/classes/com/sun/tools/javac/code/Type.java > ! src/share/classes/com/sun/tools/javac/code/Types.java > ! src/share/classes/com/sun/tools/javac/comp/Attr.java > ! src/share/classes/com/sun/tools/javac/comp/Check.java > ! src/share/classes/com/sun/tools/javac/comp/Flow.java > ! src/share/classes/com/sun/tools/javac/comp/Lower.java > ! src/share/classes/com/sun/tools/javac/comp/Resolve.java > ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java > ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java > ! src/share/classes/com/sun/tools/javac/parser/Scanner.java > ! src/share/classes/com/sun/tools/javac/parser/Token.java > ! src/share/classes/com/sun/tools/javac/resources/compiler.properties > ! src/share/classes/com/sun/tools/javac/tree/JCTree.java > ! src/share/classes/com/sun/tools/javac/tree/Pretty.java > ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java > ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java > ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java > ! src/share/classes/com/sun/tools/javac/util/Names.java > ! > src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java > + test/tools/javac/lambda/LambdaCapture01.java > + test/tools/javac/lambda/LambdaConv01.java > + test/tools/javac/lambda/LambdaExpr01.java > + test/tools/javac/lambda/LambdaExpr02.java > + test/tools/javac/lambda/LambdaScope01.java > + test/tools/javac/lambda/NakedThis.java > + test/tools/javac/lambda/NakedThis.out > > > From neal at gafter.com Thu May 27 14:02:07 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 27 May 2010 14:02:07 -0700 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <20100527173313.6763646E4A@hg.openjdk.java.net> References: <20100527173313.6763646E4A@hg.openjdk.java.net> Message-ID: Great to see this, Maurizio! Unfortunately it arrives a week too late, and in the wrong repository, to be included in jdk7. I notice that none of the tests show a variable of function type being converted to a SAM type. What are the plans there? On Thu, May 27, 2010 at 10:33 AM, wrote: > Changeset: 7704dcd17e0b > Author: mcimadamore > Date: 2010-05-27 18:11 +0100 > URL: > http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b > > initial lambda push; the current prototype suuports the following features: > *) function types syntax (optionally enabled with -XDallowFunctionTypes) > *) function types subtyping > *) full support for lambda expression of type 1 and 2 > *) inference of thrown types/return type in a lambda > *) lambda conversion using rules specified in v0.1.5 draft > *) support references to 'this' (both explicit and implicit) > *) translation using method handles > > The modified script build of the langtools repository now generates an > additional jarfile called javacrt.jar which contains an helper class to be > used during SAM conversion; after the build, the generated scripts > javac/java will take care of automatically setting up the required > dependencies so that code containing lambda expressions can be compiled and > executed. > > ! make/build.properties > ! make/build.xml > + src/share/bin/java.sh-template > ! src/share/bin/launcher.sh-template > + src/share/classes/com/sun/runtime/ProxyHelper.java > + src/share/classes/com/sun/source/tree/FunctionTypeTree.java > + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java > ! src/share/classes/com/sun/source/tree/Tree.java > ! src/share/classes/com/sun/source/tree/TreeVisitor.java > ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java > ! src/share/classes/com/sun/source/util/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/code/Flags.java > ! src/share/classes/com/sun/tools/javac/code/Printer.java > ! src/share/classes/com/sun/tools/javac/code/Scope.java > ! src/share/classes/com/sun/tools/javac/code/Source.java > ! src/share/classes/com/sun/tools/javac/code/Symtab.java > ! src/share/classes/com/sun/tools/javac/code/Type.java > ! src/share/classes/com/sun/tools/javac/code/Types.java > ! src/share/classes/com/sun/tools/javac/comp/Attr.java > ! src/share/classes/com/sun/tools/javac/comp/Check.java > ! src/share/classes/com/sun/tools/javac/comp/Flow.java > ! src/share/classes/com/sun/tools/javac/comp/Lower.java > ! src/share/classes/com/sun/tools/javac/comp/Resolve.java > ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java > ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java > ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java > ! src/share/classes/com/sun/tools/javac/parser/Scanner.java > ! src/share/classes/com/sun/tools/javac/parser/Token.java > ! src/share/classes/com/sun/tools/javac/resources/compiler.properties > ! src/share/classes/com/sun/tools/javac/tree/JCTree.java > ! src/share/classes/com/sun/tools/javac/tree/Pretty.java > ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java > ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java > ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java > ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java > ! src/share/classes/com/sun/tools/javac/util/Names.java > ! src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java > + test/tools/javac/lambda/LambdaCapture01.java > + test/tools/javac/lambda/LambdaConv01.java > + test/tools/javac/lambda/LambdaExpr01.java > + test/tools/javac/lambda/LambdaExpr02.java > + test/tools/javac/lambda/LambdaScope01.java > + test/tools/javac/lambda/NakedThis.java > + test/tools/javac/lambda/NakedThis.out > > > From ahughes at redhat.com Wed May 19 08:53:31 2010 From: ahughes at redhat.com (Andrew John Hughes) Date: Wed, 19 May 2010 16:53:31 +0100 Subject: Reading the Tea Leaves (who's working on Project Lambda) In-Reply-To: References: Message-ID: On 19 May 2010 05:39, Neal Gafter wrote: > I noticed that two recently published documents were > > ? ?http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf > and > ? ?http://cr.openjdk.java.net/~darcy/DefenderMethods.pdf > > Both list Brian Goetz as author. > The translation document is in Maurizio Cimadamore's code review area. > The defender methods document is in Joe Darcy's code review area. > > I don't expect Oracle employees will be authorized to discuss resource > allocation, but I take this as an encouraging sign. > > It's a pity the idea of working in the open seems to have fallen by the wayside a bit :-( -- Andrew :-) Free Java Software Engineer Red Hat, Inc. (http://www.redhat.com) Support Free Java! Contribute to GNU Classpath and the OpenJDK http://www.gnu.org/software/classpath http://openjdk.java.net PGP Key: 94EFD9D8 (http://subkeys.pgp.net) Fingerprint: F8EF F1EA 401E 2E60 15FA 7927 142C 2591 94EF D9D8 From jonathan.gibbons at oracle.com Thu May 27 14:15:27 2010 From: jonathan.gibbons at oracle.com (Jonathan Gibbons) Date: Thu, 27 May 2010 14:15:27 -0700 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: References: <20100527173313.6763646E4A@hg.openjdk.java.net> Message-ID: <4BFEE0EF.805@oracle.com> On 05/27/2010 02:02 PM, Neal Gafter wrote: > Great to see this, Maurizio! Unfortunately it arrives a week too late, and > in the wrong repository, to be included in jdk7. > Neal, Since the published feature list for jdk7 and the published schedule for jdk7 would appear to be at odds, why do you always assume the schedule is correct? -- Jon From nathan.bryant at linkshare.com Thu May 27 14:27:08 2010 From: nathan.bryant at linkshare.com (Nathan Bryant) Date: Fri, 28 May 2010 06:27:08 +0900 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: References: <20100527173313.6763646E4A@hg.openjdk.java.net> Message-ID: <7FDA6630E1822F448C97A48D5D73309488A97F@EXVMSTOR302.intra.rakuten.co.jp> >I notice that none of the tests show a variable of function type being >converted to a SAM type. What are the plans there? Also not shown is a variable of function type being /declared/. Apparently the syntax (whose version of the syntax?) for doing so is there, per the initial email, just untested From neal at gafter.com Thu May 27 14:28:29 2010 From: neal at gafter.com (Neal Gafter) Date: Thu, 27 May 2010 14:28:29 -0700 Subject: hg: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFEE0EF.805@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <4BFEE0EF.805@oracle.com> Message-ID: On Thu, May 27, 2010 at 2:15 PM, Jonathan Gibbons < jonathan.gibbons at oracle.com> wrote: > Neal, > > Since the published feature list for jdk7 and the published schedule for > jdk7 would appear to be at odds, why do you always assume the schedule > is correct? > Because I recall repeated discussion to the effect that the feature set would be adjusted based on their completion status with respect to the schedule. From forax at univ-mlv.fr Thu May 27 17:37:47 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Fri, 28 May 2010 02:37:47 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFECC49.2040101@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> Message-ID: <4BFF105B.2030008@univ-mlv.fr> Nice ! I suppose that you use invokeVarargs() when invoking a lambda to workaround the current state of invokeGeneric() in b94. I will do a code review tomorrow. R?mi Le 27/05/2010 21:47, maurizio cimadamore a ?crit : > Hi > The prototype supports the syntax described in the strawman proposal > [1]. You might want to look at some of the regression tests, in > particular LambdaExpr01/LambdaExpr02 [2,3] to get an idea of what the > syntax look like. > > Thanks > Maurizio > > [1] > http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt > [2] > http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr01.java > [3] > http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr02.java > > On 27/05/10 18:45, Nathan Bryant wrote: > >> This is great! But what is the syntax? >> >> -----Original Message----- >> From: lambda-dev-bounces at openjdk.java.net >> [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of >> maurizio.cimadamore at oracle.com >> Sent: Thursday, May 27, 2010 1:33 PM >> To: lambda-dev at openjdk.java.net >> Subject: hg: lambda/lambda/langtools: initial lambda push;the current >> prototype suuports the following features: >> >> Changeset: 7704dcd17e0b >> Author: mcimadamore >> Date: 2010-05-27 18:11 +0100 >> URL: >> http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b >> >> initial lambda push; the current prototype suuports the following >> features: >> *) function types syntax (optionally enabled with -XDallowFunctionTypes) >> *) function types subtyping >> *) full support for lambda expression of type 1 and 2 >> *) inference of thrown types/return type in a lambda >> *) lambda conversion using rules specified in v0.1.5 draft >> *) support references to 'this' (both explicit and implicit) >> *) translation using method handles >> >> The modified script build of the langtools repository now generates an >> additional jarfile called javacrt.jar which contains an helper class to >> be used during SAM conversion; after the build, the generated scripts >> javac/java will take care of automatically setting up the required >> dependencies so that code containing lambda expressions can be compiled >> and executed. >> >> ! make/build.properties >> ! make/build.xml >> + src/share/bin/java.sh-template >> ! src/share/bin/launcher.sh-template >> + src/share/classes/com/sun/runtime/ProxyHelper.java >> + src/share/classes/com/sun/source/tree/FunctionTypeTree.java >> + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java >> ! src/share/classes/com/sun/source/tree/Tree.java >> ! src/share/classes/com/sun/source/tree/TreeVisitor.java >> ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java >> ! src/share/classes/com/sun/source/util/TreeScanner.java >> ! src/share/classes/com/sun/tools/javac/code/Flags.java >> ! src/share/classes/com/sun/tools/javac/code/Printer.java >> ! src/share/classes/com/sun/tools/javac/code/Scope.java >> ! src/share/classes/com/sun/tools/javac/code/Source.java >> ! src/share/classes/com/sun/tools/javac/code/Symtab.java >> ! src/share/classes/com/sun/tools/javac/code/Type.java >> ! src/share/classes/com/sun/tools/javac/code/Types.java >> ! src/share/classes/com/sun/tools/javac/comp/Attr.java >> ! src/share/classes/com/sun/tools/javac/comp/Check.java >> ! src/share/classes/com/sun/tools/javac/comp/Flow.java >> ! src/share/classes/com/sun/tools/javac/comp/Lower.java >> ! src/share/classes/com/sun/tools/javac/comp/Resolve.java >> ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java >> ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java >> ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java >> ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java >> ! src/share/classes/com/sun/tools/javac/parser/Scanner.java >> ! src/share/classes/com/sun/tools/javac/parser/Token.java >> ! src/share/classes/com/sun/tools/javac/resources/compiler.properties >> ! src/share/classes/com/sun/tools/javac/tree/JCTree.java >> ! src/share/classes/com/sun/tools/javac/tree/Pretty.java >> ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java >> ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java >> ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java >> ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java >> ! src/share/classes/com/sun/tools/javac/util/Names.java >> ! >> src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java >> + test/tools/javac/lambda/LambdaCapture01.java >> + test/tools/javac/lambda/LambdaConv01.java >> + test/tools/javac/lambda/LambdaExpr01.java >> + test/tools/javac/lambda/LambdaExpr02.java >> + test/tools/javac/lambda/LambdaScope01.java >> + test/tools/javac/lambda/NakedThis.java >> + test/tools/javac/lambda/NakedThis.out >> >> >> >> > > From maurizio.cimadamore at oracle.com Fri May 28 01:36:45 2010 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 28 May 2010 09:36:45 +0100 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFF105B.2030008@univ-mlv.fr> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> Message-ID: <4BFF809D.8000801@oracle.com> On 28/05/10 01:37, R?mi Forax wrote: > Nice ! > I suppose that you use invokeVarargs() when invoking a lambda to workaround > the current state of invokeGeneric() in b94. > Hi Remi, you are quite correct, the generated code currently uses the invokeVarargs. Also, method handles are created reflectively (using MethodHandles.lookup()), which is sub-optimal. Maurizio > I will do a code review tomorrow. > > R?mi > > > Le 27/05/2010 21:47, maurizio cimadamore a ?crit : > >> Hi >> The prototype supports the syntax described in the strawman proposal >> [1]. You might want to look at some of the regression tests, in >> particular LambdaExpr01/LambdaExpr02 [2,3] to get an idea of what the >> syntax look like. >> >> Thanks >> Maurizio >> >> [1] >> http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt >> [2] >> http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr01.java >> [3] >> http://hg.openjdk.java.net/lambda/lambda/langtools/diff/7704dcd17e0b/test/tools/javac/lambda/LambdaExpr02.java >> >> On 27/05/10 18:45, Nathan Bryant wrote: >> >> >>> This is great! But what is the syntax? >>> >>> -----Original Message----- >>> From: lambda-dev-bounces at openjdk.java.net >>> [mailto:lambda-dev-bounces at openjdk.java.net] On Behalf Of >>> maurizio.cimadamore at oracle.com >>> Sent: Thursday, May 27, 2010 1:33 PM >>> To: lambda-dev at openjdk.java.net >>> Subject: hg: lambda/lambda/langtools: initial lambda push;the current >>> prototype suuports the following features: >>> >>> Changeset: 7704dcd17e0b >>> Author: mcimadamore >>> Date: 2010-05-27 18:11 +0100 >>> URL: >>> http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7704dcd17e0b >>> >>> initial lambda push; the current prototype suuports the following >>> features: >>> *) function types syntax (optionally enabled with -XDallowFunctionTypes) >>> *) function types subtyping >>> *) full support for lambda expression of type 1 and 2 >>> *) inference of thrown types/return type in a lambda >>> *) lambda conversion using rules specified in v0.1.5 draft >>> *) support references to 'this' (both explicit and implicit) >>> *) translation using method handles >>> >>> The modified script build of the langtools repository now generates an >>> additional jarfile called javacrt.jar which contains an helper class to >>> be used during SAM conversion; after the build, the generated scripts >>> javac/java will take care of automatically setting up the required >>> dependencies so that code containing lambda expressions can be compiled >>> and executed. >>> >>> ! make/build.properties >>> ! make/build.xml >>> + src/share/bin/java.sh-template >>> ! src/share/bin/launcher.sh-template >>> + src/share/classes/com/sun/runtime/ProxyHelper.java >>> + src/share/classes/com/sun/source/tree/FunctionTypeTree.java >>> + src/share/classes/com/sun/source/tree/LambdaExpressionTree.java >>> ! src/share/classes/com/sun/source/tree/Tree.java >>> ! src/share/classes/com/sun/source/tree/TreeVisitor.java >>> ! src/share/classes/com/sun/source/util/SimpleTreeVisitor.java >>> ! src/share/classes/com/sun/source/util/TreeScanner.java >>> ! src/share/classes/com/sun/tools/javac/code/Flags.java >>> ! src/share/classes/com/sun/tools/javac/code/Printer.java >>> ! src/share/classes/com/sun/tools/javac/code/Scope.java >>> ! src/share/classes/com/sun/tools/javac/code/Source.java >>> ! src/share/classes/com/sun/tools/javac/code/Symtab.java >>> ! src/share/classes/com/sun/tools/javac/code/Type.java >>> ! src/share/classes/com/sun/tools/javac/code/Types.java >>> ! src/share/classes/com/sun/tools/javac/comp/Attr.java >>> ! src/share/classes/com/sun/tools/javac/comp/Check.java >>> ! src/share/classes/com/sun/tools/javac/comp/Flow.java >>> ! src/share/classes/com/sun/tools/javac/comp/Lower.java >>> ! src/share/classes/com/sun/tools/javac/comp/Resolve.java >>> ! src/share/classes/com/sun/tools/javac/comp/TransTypes.java >>> ! src/share/classes/com/sun/tools/javac/jvm/ClassReader.java >>> ! src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java >>> ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java >>> ! src/share/classes/com/sun/tools/javac/parser/Scanner.java >>> ! src/share/classes/com/sun/tools/javac/parser/Token.java >>> ! src/share/classes/com/sun/tools/javac/resources/compiler.properties >>> ! src/share/classes/com/sun/tools/javac/tree/JCTree.java >>> ! src/share/classes/com/sun/tools/javac/tree/Pretty.java >>> ! src/share/classes/com/sun/tools/javac/tree/TreeCopier.java >>> ! src/share/classes/com/sun/tools/javac/tree/TreeMaker.java >>> ! src/share/classes/com/sun/tools/javac/tree/TreeScanner.java >>> ! src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java >>> ! src/share/classes/com/sun/tools/javac/util/Names.java >>> ! >>> src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java >>> + test/tools/javac/lambda/LambdaCapture01.java >>> + test/tools/javac/lambda/LambdaConv01.java >>> + test/tools/javac/lambda/LambdaExpr01.java >>> + test/tools/javac/lambda/LambdaExpr02.java >>> + test/tools/javac/lambda/LambdaScope01.java >>> + test/tools/javac/lambda/NakedThis.java >>> + test/tools/javac/lambda/NakedThis.out >>> >>> >>> >>> >>> >> >> > > From maurizio.cimadamore at oracle.com Fri May 28 02:50:27 2010 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Fri, 28 May 2010 09:50:27 +0000 Subject: hg: lambda/lambda/langtools: *) Fixed lambda conversion bug involving handling of void type Message-ID: <20100528095038.CED4B46E6B@hg.openjdk.java.net> Changeset: 317bac39b8a4 Author: mcimadamore Date: 2010-05-28 10:45 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/317bac39b8a4 *) Fixed lambda conversion bug involving handling of void type *) Added regression test showing usage of function types (LambdaConv02.java) ! src/share/classes/com/sun/tools/javac/code/Types.java ! src/share/classes/com/sun/tools/javac/comp/Lower.java + test/tools/javac/lambda/LambdaConv02.java From maurizio.cimadamore at oracle.com Fri May 28 04:15:09 2010 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Fri, 28 May 2010 11:15:09 +0000 Subject: hg: lambda/lambda/langtools: Added interoperability between method type-inference, function types and SAM conversion (as per strawman spec v0.1.5) Message-ID: <20100528111511.B7F7046E73@hg.openjdk.java.net> Changeset: 7586844b51d3 Author: mcimadamore Date: 2010-05-28 12:12 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7586844b51d3 Added interoperability between method type-inference, function types and SAM conversion (as per strawman spec v0.1.5) See tests LambdaConv03.java and LambdaConv04.java for examples. ! src/share/classes/com/sun/tools/javac/code/Types.java ! src/share/classes/com/sun/tools/javac/comp/Attr.java ! src/share/classes/com/sun/tools/javac/comp/Lower.java + test/tools/javac/lambda/LambdaConv03.java + test/tools/javac/lambda/LambdaConv04.java From forax at univ-mlv.fr Fri May 28 07:40:47 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Fri, 28 May 2010 16:40:47 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFF809D.8000801@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> Message-ID: <4BFFD5EF.9020909@univ-mlv.fr> I've found some bugs :) // this doesn't compile - how to declare a function type that doesn't takes any parameter ? #int() bar; // in my opinion, an instruction can start with a lambda that has a body, // but the hand-coded grammar of the compiler doesn't allow that. #(int x) { System.out.println(x); }.(); // Open question: can an instruction starts with a lambda expression ? // this snippet generate invalid code (at bytecode offset 4) int v = #(Object o) { System.out.println(this.type()); return 3; }.("foo"); static int lambda$0(java.dyn.MethodHandle, java.lang.Object); Code: 0: getstatic #1 // Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: invokevirtual #2 // Method "".type:()Ljava/dyn/MethodType; 7: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 10: iconst_3 11: ireturn R?mi From maurizio.cimadamore at oracle.com Fri May 28 08:04:51 2010 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 28 May 2010 16:04:51 +0100 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFFD5EF.9020909@univ-mlv.fr> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> Message-ID: <4BFFDB93.5060804@oracle.com> On 28/05/10 15:40, R?mi Forax wrote: > I've found some bugs :) > > // this doesn't compile - how to declare a function type that doesn't > takes any parameter ? > #int() bar; I'm in the process of fixing this... > > > // in my opinion, an instruction can start with a lambda that has a body, > // but the hand-coded grammar of the compiler doesn't allow that. > #(int x) { System.out.println(x); }.(); > > // Open question: can an instruction starts with a lambda expression ? Good question; my choice has been to make lambda a plain expression, rather than an expression statement; this way it is mandatory to always wrap a lambda either within a function type or within a SAM type. > > > // this snippet generate invalid code (at bytecode offset 4) > int v = #(Object o) { > System.out.println(this.type()); > return 3; > }.("foo"); the .type() syntax is not supported yet, hence the bad bytecode. Thanks for the headsup! Maurizio > > static int lambda$0(java.dyn.MethodHandle, java.lang.Object); > Code: > 0: getstatic #1 // Field > java/lang/System.out:Ljava/io/PrintStream; > 3: aload_0 > 4: invokevirtual #2 // Method > "".type:()Ljava/dyn/MethodType; > 7: invokevirtual #3 // Method > java/io/PrintStream.println:(Ljava/lang/Object;)V > 10: iconst_3 > 11: ireturn > > > R?mi > From maurizio.cimadamore at oracle.com Fri May 28 09:21:10 2010 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Fri, 28 May 2010 16:21:10 +0000 Subject: hg: lambda/lambda/langtools: Added simple lookahead in order to disambiguate between lambda expression and variable declaration of function types. Message-ID: <20100528162112.D91A246E78@hg.openjdk.java.net> Changeset: 81966684ef23 Author: mcimadamore Date: 2010-05-28 17:19 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/81966684ef23 Added simple lookahead in order to disambiguate between lambda expression and variable declaration of function types. ! src/share/classes/com/sun/tools/javac/parser/JavacParser.java ! src/share/classes/com/sun/tools/javac/parser/Lexer.java ! src/share/classes/com/sun/tools/javac/parser/Scanner.java + test/tools/javac/lambda/FuncType01.java ! test/tools/javac/lambda/LambdaCapture01.java + test/tools/javac/lambda/LambdaExpr03.java From mingyeeiu+lambda at gmail.com Fri May 28 12:26:06 2010 From: mingyeeiu+lambda at gmail.com (Ming-Yee Iu) Date: Fri, 28 May 2010 21:26:06 +0200 Subject: Translation Using asSam() and LINQ for Java Message-ID: I'm concerned that translating lambda expressions to bytecode using MethodHandles and asSam() will make it difficult if not impossible to create some sort of LINQ-equivalent for Java. If lambda expressions are compiled down to inner-classes, then someone could add LINQ functionality to JDK7 using a clever classloader (as long as there is automatic closure conversion to interfaces or support for annotations on lambda expressions). When using MethodHandles and asSam(), my gut feeling is that it is not possible to implement something like LINQ without having a special compiler for a LINQ-supporting-variant of Java. Perhaps JDK7 could use only inner classes for its anonymous functions, and this asSam() stuff could be delayed until JDK8 when people have more experience with what they want to do with lambda expressions. -Ming From alessiostalla at gmail.com Fri May 28 12:38:33 2010 From: alessiostalla at gmail.com (Alessio Stalla) Date: Fri, 28 May 2010 21:38:33 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: On Fri, May 28, 2010 at 9:26 PM, Ming-Yee Iu wrote: > I'm concerned that translating lambda expressions to bytecode using > MethodHandles and asSam() will make it difficult if not impossible to > create some sort of LINQ-equivalent for Java. >[snip] Please forgive my ignorance, but isn't LINQ a purely compile-time transformation? Alessio From neal at gafter.com Fri May 28 12:46:33 2010 From: neal at gafter.com (Neal Gafter) Date: Fri, 28 May 2010 12:46:33 -0700 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: Ming-Yee- It is true that project lambda doesn't appear to be offering the primitives that would be required to get LINQ-like behavior in Java, but I don't believe classloader hacking is the right way to do it. Cheers, Neal On Fri, May 28, 2010 at 12:26 PM, Ming-Yee Iu > wrote: > I'm concerned that translating lambda expressions to bytecode using > MethodHandles and asSam() will make it difficult if not impossible to > create some sort of LINQ-equivalent for Java. > > If lambda expressions are compiled down to inner-classes, then someone > could add LINQ functionality to JDK7 using a clever classloader (as > long as there is automatic closure conversion to interfaces or support > for annotations on lambda expressions). When using MethodHandles and > asSam(), my gut feeling is that it is not possible to implement > something like LINQ without having a special compiler for a > LINQ-supporting-variant of Java. > > Perhaps JDK7 could use only inner classes for its anonymous functions, > and this asSam() stuff could be delayed until JDK8 when people have > more experience with what they want to do with lambda expressions. > > -Ming > > From mingyeeiu+lambda at gmail.com Sat May 29 00:16:34 2010 From: mingyeeiu+lambda at gmail.com (Ming-Yee Iu) Date: Sat, 29 May 2010 09:16:34 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: > Please forgive my ignorance, but isn't LINQ a purely compile-time > transformation? > > Alessio Yes, LINQ, as implemented by Microsoft, is a purely compile-time transformation. Although Oracle now directs Java, it will probably take a long, long time for compiler support for database queries to be added to Java, if ever. So the most practical way to add support LINQ-style queries to Java within the next 5 years would be through classloader tricks or other bytecode rewriting techniques. Unfortunately, using asSam() for lambda expressions causes problems for this bytecode rewriting. These are the particular problems that I can see right now: Consider the query final String parameter = "UK"; Collection results = database.getAccounts().where( #(Account a) a.getCountry().equals(parameter)); in which the where() method is declared with a signature like public ResultSet where(WhereRestriction) and in which the where() method is expected to generate the database query SELECT * FROM Accounts WHERE Country = ? 1. During bytecode analysis, it's not possible to determine which code to analyze. When translating using inner classes, the bytecode analyzer in the classloader can simply look for classes that implement the WhereRestriction interface. When asSam() is used, it is hard to determine that a particular method is intended to be used in a query since the conversion of a method to a WhereRestriction is done at runtime. 2. The where() method needs to crack out the query parameters from the lambda expression that it is given. With inner classes, the query parameters are stored as fields in the inner class, so the where() method can use reflection or bytecode rewriting to get access to these parameters. Using the asSam() approach, the parameters are hidden inside some runtime-generated opaque object. 3. The where() method needs to know which lambda expression it was given. With inner classes, the reference given to the where() method directly correlates to the code, so the where() can do something like public where(WhereRestriction w) if w.class is OuterClass$InnerClass then ... But with asSam(), there is no way for the where() method to know which lambda expression it was given because the lambda expression has been wrapped by a runtime-generated opaque object. --- There are probably workarounds for these issues, but the trade-off is much more complexity--to the point where this avenue for adding LINQ-style queries to Java may become infeasible. -Ming From mingyeeiu+lambda at gmail.com Sat May 29 00:25:29 2010 From: mingyeeiu+lambda at gmail.com (Ming-Yee Iu) Date: Sat, 29 May 2010 09:25:29 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: Sure. It's not clear exactly what people will want to do with closures once JDK7 is released. Creating a variant of LINQ in Java using closures and heavy bytecode analysis is, perhaps, not something that people want to do. But I just wanted people to know that if they do go the asSam() route, then this avenue is likely closed. Then, they can more properly evaluate the trade-offs of their particular closure implementation. -Ming On Fri, May 28, 2010 at 9:46 PM, Neal Gafter wrote: > Ming-Yee- > > It is true that project lambda doesn't appear to be offering the primitives > that would be required to get LINQ-like behavior in Java, but I don't > believe classloader hacking is the right way to do it. > > Cheers, > Neal > > On Fri, May 28, 2010 at 12:26 PM, Ming-Yee Iu > wrote: >> >> I'm concerned that translating lambda expressions to bytecode using >> MethodHandles and asSam() will make it difficult if not impossible to >> create some sort of LINQ-equivalent for Java. >> >> If lambda expressions are compiled down to inner-classes, then someone >> could add LINQ functionality to JDK7 using a clever classloader (as >> long as there is automatic closure conversion to interfaces or support >> for annotations on lambda expressions). When using MethodHandles and >> asSam(), my gut feeling is that it is not possible to implement >> something like LINQ without having a special compiler for a >> LINQ-supporting-variant of Java. >> >> Perhaps JDK7 could use only inner classes for its anonymous functions, >> and this asSam() stuff could be delayed until JDK8 when people have >> more experience with what they want to do with lambda expressions. >> >> -Ming >> > > From forax at univ-mlv.fr Sat May 29 06:17:06 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 15:17:06 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: <4C0113D2.9040504@univ-mlv.fr> As far as I know the JCP runs Java. Oracle is a database company, so the problem can be seen in the opposite way, instead of transforming a lambda to tree why not serializing the lambda to be directly available to the database. R?mi Le 29/05/2010 09:16, Ming-Yee Iu a ?crit : >> Please forgive my ignorance, but isn't LINQ a purely compile-time >> transformation? >> >> Alessio >> > Yes, LINQ, as implemented by Microsoft, is a purely compile-time > transformation. Although Oracle now directs Java, it will probably > take a long, long time for compiler support for database queries to be > added to Java, if ever. > > So the most practical way to add support LINQ-style queries to Java > within the next 5 years would be through classloader tricks or other > bytecode rewriting techniques. Unfortunately, using asSam() for lambda > expressions causes problems for this bytecode rewriting. > > These are the particular problems that I can see right now: > > Consider the query > > final String parameter = "UK"; > Collection results = database.getAccounts().where( > #(Account a) a.getCountry().equals(parameter)); > > in which the where() method is declared with a signature like > > public ResultSet where(WhereRestriction) > > and in which the where() method is expected to generate the database query > > SELECT * FROM Accounts WHERE Country = ? > > 1. During bytecode analysis, it's not possible to determine which code > to analyze. When translating using inner classes, the bytecode > analyzer in the classloader can simply look for classes that implement > the WhereRestriction interface. When asSam() is used, it is hard to > determine that a particular method is intended to be used in a query > since the conversion of a method to a WhereRestriction is done at > runtime. > > 2. The where() method needs to crack out the query parameters from the > lambda expression that it is given. With inner classes, the query > parameters are stored as fields in the inner class, so the where() > method can use reflection or bytecode rewriting to get access to these > parameters. Using the asSam() approach, the parameters are hidden > inside some runtime-generated opaque object. > > 3. The where() method needs to know which lambda expression it was > given. With inner classes, the reference given to the where() method > directly correlates to the code, so the where() can do something like > > public where(WhereRestriction w) > if w.class is OuterClass$InnerClass then > ... > > But with asSam(), there is no way for the where() method to know which > lambda expression it was given because the lambda expression has been > wrapped by a runtime-generated opaque object. > > --- > > There are probably workarounds for these issues, but the trade-off is > much more complexity--to the point where this avenue for adding > LINQ-style queries to Java may become infeasible. > > -Ming > > From forax at univ-mlv.fr Sat May 29 07:14:34 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 16:14:34 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFFDB93.5060804@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> Message-ID: <4C01214A.6000704@univ-mlv.fr> I've tried a swearword but legal: #()(#(){}).(); The compiler knows more slang words than me :) R?mi An exception has occurred in the compiler (1.7.0-internal). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you. java.lang.NullPointerException at com.sun.tools.javac.comp.Lower.lambdaName(Lower.java:3400) at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3404) at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) at com.sun.tools.javac.comp.Lower.visitReturn(Lower.java:3155) at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1230) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) at com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) at com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3466) at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.visitSelect(Lower.java:3538) at com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:1727) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2625) at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.visitTypeCast(Lower.java:2422) at com.sun.tools.javac.tree.JCTree$JCTypeCast.accept(JCTree.java:1644) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) at com.sun.tools.javac.comp.Lower.visitLambdaCall(Lower.java:2651) at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2563) at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:242) at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1157) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) at com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) at com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:2064) at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:596) at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) at com.sun.tools.javac.comp.Lower.translate(Lower.java:1978) at com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3589) at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1328) at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1206) at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:842) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:801) at com.sun.tools.javac.main.Main.compile(Main.java:412) at com.sun.tools.javac.main.Main.compile(Main.java:330) at com.sun.tools.javac.main.Main.compile(Main.java:321) at com.sun.tools.javac.Main.compile(Main.java:82) at com.sun.tools.javac.Main.main(Main.java:67) Le 28/05/2010 17:04, Maurizio Cimadamore a ?crit : > On 28/05/10 15:40, R?mi Forax wrote: >> I've found some bugs :) >> >> // this doesn't compile - how to declare a function type that doesn't >> takes any parameter ? >> #int() bar; > > I'm in the process of fixing this... >> >> >> // in my opinion, an instruction can start with a lambda that has a >> body, >> // but the hand-coded grammar of the compiler doesn't allow that. >> #(int x) { System.out.println(x); }.(); >> >> // Open question: can an instruction starts with a lambda expression ? > Good question; my choice has been to make lambda a plain expression, > rather than an expression statement; this way it is mandatory to > always wrap a lambda either within a function type or within a SAM type. >> >> >> // this snippet generate invalid code (at bytecode offset 4) >> int v = #(Object o) { >> System.out.println(this.type()); >> return 3; >> }.("foo"); > > the .type() syntax is not supported yet, hence the bad bytecode. > > Thanks for the headsup! > > Maurizio > >> >> static int lambda$0(java.dyn.MethodHandle, java.lang.Object); >> Code: >> 0: getstatic #1 // Field >> java/lang/System.out:Ljava/io/PrintStream; >> 3: aload_0 >> 4: invokevirtual #2 // Method >> "".type:()Ljava/dyn/MethodType; >> 7: invokevirtual #3 // Method >> java/io/PrintStream.println:(Ljava/lang/Object;)V >> 10: iconst_3 >> 11: ireturn >> >> >> R?mi >> > From forax at univ-mlv.fr Sat May 29 07:31:08 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 16:31:08 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4C01214A.6000704@univ-mlv.fr> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> <4C01214A.6000704@univ-mlv.fr> Message-ID: <4C01252C.1030603@univ-mlv.fr> There is also a parsing problem: ##int()() a; It's the type of a function that returns a function that returns an int. LambdaClash.java:23: throws expected ##int()() a; ^ R?mi Le 29/05/2010 16:14, R?mi Forax a ?crit : > I've tried a swearword but legal: > > #()(#(){}).(); > > The compiler knows more slang words than me :) > > R?mi > > An exception has occurred in the compiler (1.7.0-internal). Please file > a bug at the Java Developer Connection > (http://java.sun.com/webapps/bugreport) after checking the Bug Parade > for duplicates. Include your program and the following diagnostic in > your report. Thank you. > java.lang.NullPointerException > at com.sun.tools.javac.comp.Lower.lambdaName(Lower.java:3400) > at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3404) > at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) > at com.sun.tools.javac.comp.Lower.visitReturn(Lower.java:3155) > at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1230) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) > at > com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) > at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) > at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) > at > com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) > at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) > at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3466) > at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitSelect(Lower.java:3538) > at > com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:1727) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2625) > at > com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitTypeCast(Lower.java:2422) > at com.sun.tools.javac.tree.JCTree$JCTypeCast.accept(JCTree.java:1644) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) > at com.sun.tools.javac.comp.Lower.visitLambdaCall(Lower.java:2651) > at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2563) > at > com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:242) > at > com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1157) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) > at > com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) > at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) > at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) > at > com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) > at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) > at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:2064) > at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:596) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1978) > at > com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3589) > at > com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1328) > at > com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1206) > at > com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:842) > at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:801) > at com.sun.tools.javac.main.Main.compile(Main.java:412) > at com.sun.tools.javac.main.Main.compile(Main.java:330) > at com.sun.tools.javac.main.Main.compile(Main.java:321) > at com.sun.tools.javac.Main.compile(Main.java:82) > at com.sun.tools.javac.Main.main(Main.java:67) > > > > Le 28/05/2010 17:04, Maurizio Cimadamore a ?crit : > >> On 28/05/10 15:40, R?mi Forax wrote: >> >>> I've found some bugs :) >>> >>> // this doesn't compile - how to declare a function type that doesn't >>> takes any parameter ? >>> #int() bar; >>> >> I'm in the process of fixing this... >> >>> >>> // in my opinion, an instruction can start with a lambda that has a >>> body, >>> // but the hand-coded grammar of the compiler doesn't allow that. >>> #(int x) { System.out.println(x); }.(); >>> >>> // Open question: can an instruction starts with a lambda expression ? >>> >> Good question; my choice has been to make lambda a plain expression, >> rather than an expression statement; this way it is mandatory to >> always wrap a lambda either within a function type or within a SAM type. >> >>> >>> // this snippet generate invalid code (at bytecode offset 4) >>> int v = #(Object o) { >>> System.out.println(this.type()); >>> return 3; >>> }.("foo"); >>> >> the .type() syntax is not supported yet, hence the bad bytecode. >> >> Thanks for the headsup! >> >> Maurizio >> >> >>> static int lambda$0(java.dyn.MethodHandle, java.lang.Object); >>> Code: >>> 0: getstatic #1 // Field >>> java/lang/System.out:Ljava/io/PrintStream; >>> 3: aload_0 >>> 4: invokevirtual #2 // Method >>> "".type:()Ljava/dyn/MethodType; >>> 7: invokevirtual #3 // Method >>> java/io/PrintStream.println:(Ljava/lang/Object;)V >>> 10: iconst_3 >>> 11: ireturn >>> >>> >>> R?mi >>> >>> >> > > From forax at univ-mlv.fr Sat May 29 07:44:04 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 16:44:04 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFFDB93.5060804@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> Message-ID: <4C012834.7030002@univ-mlv.fr> Le 28/05/2010 17:04, Maurizio Cimadamore a ?crit : > On 28/05/10 15:40, R?mi Forax wrote: >> I've found some bugs :) >> >> // this doesn't compile - how to declare a function type that doesn't >> takes any parameter ? >> #int() bar; > > I'm in the process of fixing this... Ok, it now works. >> >> >> // in my opinion, an instruction can start with a lambda that has a >> body, >> // but the hand-coded grammar of the compiler doesn't allow that. >> #(int x) { System.out.println(x); }.(); >> >> // Open question: can an instruction starts with a lambda expression ? > Good question; my choice has been to make lambda a plain expression, > rather than an expression statement; this way it is mandatory to > always wrap a lambda either within a function type or within a SAM type. So the following code is legal even if it's stupid. #() (2).(); Catching this case requires to complexify the grammar so I think it doesn't worth it. I can live with that. R?mi From forax at univ-mlv.fr Sat May 29 14:11:56 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 23:11:56 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4BFFDB93.5060804@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> Message-ID: <4C01831C.4060708@univ-mlv.fr> >> // this snippet generate invalid code (at bytecode offset 4) >> int v = #(Object o) { >> System.out.println(this.type()); >> return 3; >> }.("foo"); > > the .type() syntax is not supported yet, hence the bad bytecode. Not sure, it's the only problem System.out.println(#() (this.toString()).()); and System.out.println(#() (toString()).()); also produces ill formed bytecode. > > Thanks for the headsup! > > Maurizio R?mi From forax at univ-mlv.fr Sat May 29 14:50:53 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 29 May 2010 23:50:53 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4C01831C.4060708@univ-mlv.fr> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> <4C01831C.4060708@univ-mlv.fr> Message-ID: <4C018C3D.90505@univ-mlv.fr> Le 29/05/2010 23:11, R?mi Forax a ?crit : > >>> // this snippet generate invalid code (at bytecode offset 4) >>> int v = #(Object o) { >>> System.out.println(this.type()); >>> return 3; >>> }.("foo"); >>> >> the .type() syntax is not supported yet, hence the bad bytecode. >> > Not sure, it's the only problem > I mean, it's *not* the only problem > System.out.println(#() (this.toString()).()); > and > System.out.println(#() (toString()).()); > also produces ill formed bytecode. > > >> Thanks for the headsup! >> >> Maurizio >> > R?mi > > From maurizio.cimadamore at oracle.com Sat May 29 15:23:00 2010 From: maurizio.cimadamore at oracle.com (maurizio cimadamore) Date: Sat, 29 May 2010 23:23:00 +0100 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4C01214A.6000704@univ-mlv.fr> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> <4C01214A.6000704@univ-mlv.fr> Message-ID: <4C0193C4.5000906@oracle.com> On 29/05/2010 15:14, R?mi Forax wrote: > I've tried a swearword but legal: > > #()(#(){}).(); Hey, congrats! This one wins the 'lambda of the week' award hands down! ;-) Maurizio > > The compiler knows more slang words than me :) > > R?mi > > An exception has occurred in the compiler (1.7.0-internal). Please > file a bug at the Java Developer Connection > (http://java.sun.com/webapps/bugreport) after checking the Bug Parade > for duplicates. Include your program and the following diagnostic in > your report. Thank you. > java.lang.NullPointerException > at com.sun.tools.javac.comp.Lower.lambdaName(Lower.java:3400) > at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3404) > at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) > at com.sun.tools.javac.comp.Lower.visitReturn(Lower.java:3155) > at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1230) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) > at > com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) > > at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) > at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) > > at > com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) > at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) > at > com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitLambda(Lower.java:3466) > at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1452) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitSelect(Lower.java:3538) > at > com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:1727) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2625) > at > com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) > > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitTypeCast(Lower.java:2422) > at > com.sun.tools.javac.tree.JCTree$JCTypeCast.accept(JCTree.java:1644) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1970) > at com.sun.tools.javac.comp.Lower.visitLambdaCall(Lower.java:2651) > at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2563) > at > com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1311) > > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:242) > > at > com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1157) > > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:70) > at > com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:160) > > at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:3128) > at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:780) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at > com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:144) > > at > com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2407) > at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2326) > at > com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:667) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:2064) > at > com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:596) > at > com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1958) > at com.sun.tools.javac.comp.Lower.translate(Lower.java:1978) > at > com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3589) > at > com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1328) > at > com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1206) > at > com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:842) > at > com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:801) > at com.sun.tools.javac.main.Main.compile(Main.java:412) > at com.sun.tools.javac.main.Main.compile(Main.java:330) > at com.sun.tools.javac.main.Main.compile(Main.java:321) > at com.sun.tools.javac.Main.compile(Main.java:82) > at com.sun.tools.javac.Main.main(Main.java:67) > > > > Le 28/05/2010 17:04, Maurizio Cimadamore a ?crit : >> On 28/05/10 15:40, R?mi Forax wrote: >>> I've found some bugs :) >>> >>> // this doesn't compile - how to declare a function type that >>> doesn't takes any parameter ? >>> #int() bar; >> >> I'm in the process of fixing this... >>> >>> >>> // in my opinion, an instruction can start with a lambda that has a >>> body, >>> // but the hand-coded grammar of the compiler doesn't allow that. >>> #(int x) { System.out.println(x); }.(); >>> >>> // Open question: can an instruction starts with a lambda expression ? >> Good question; my choice has been to make lambda a plain expression, >> rather than an expression statement; this way it is mandatory to >> always wrap a lambda either within a function type or within a SAM type. >>> >>> >>> // this snippet generate invalid code (at bytecode offset 4) >>> int v = #(Object o) { >>> System.out.println(this.type()); >>> return 3; >>> }.("foo"); >> >> the .type() syntax is not supported yet, hence the bad bytecode. >> >> Thanks for the headsup! >> >> Maurizio >> >>> >>> static int lambda$0(java.dyn.MethodHandle, java.lang.Object); >>> Code: >>> 0: getstatic #1 // Field >>> java/lang/System.out:Ljava/io/PrintStream; >>> 3: aload_0 >>> 4: invokevirtual #2 // Method >>> "".type:()Ljava/dyn/MethodType; >>> 7: invokevirtual #3 // Method >>> java/io/PrintStream.println:(Ljava/lang/Object;)V >>> 10: iconst_3 >>> 11: ireturn >>> >>> >>> R?mi >>> >> > From forax at univ-mlv.fr Sun May 30 03:46:40 2010 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sun, 30 May 2010 12:46:40 +0200 Subject: lambda/lambda/langtools: initial lambda push; the current prototype suuports the following features: In-Reply-To: <4C0193C4.5000906@oracle.com> References: <20100527173313.6763646E4A@hg.openjdk.java.net> <7FDA6630E1822F448C97A48D5D73309482E4CE@EXVMSTOR302.intra.rakuten.co.jp> <4BFECC49.2040101@oracle.com> <4BFF105B.2030008@univ-mlv.fr> <4BFF809D.8000801@oracle.com> <4BFFD5EF.9020909@univ-mlv.fr> <4BFFDB93.5060804@oracle.com> <4C01214A.6000704@univ-mlv.fr> <4C0193C4.5000906@oracle.com> Message-ID: <4C024210.2070602@univ-mlv.fr> Le 30/05/2010 00:23, maurizio cimadamore a ?crit : > On 29/05/2010 15:14, R?mi Forax wrote: >> I've tried a swearword but legal: >> >> #()(#(){}).(); > Hey, congrats! This one wins the 'lambda of the week' award hands > down! ;-) It's just the famous triple whopper which cheese smiley :) > > Maurizio R?mi From alessiostalla at gmail.com Sun May 30 07:18:35 2010 From: alessiostalla at gmail.com (Alessio Stalla) Date: Sun, 30 May 2010 16:18:35 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: On Sat, May 29, 2010 at 9:16 AM, Ming-Yee Iu wrote: >> Please forgive my ignorance, but isn't LINQ a purely compile-time >> transformation? >> >> Alessio > > Yes, LINQ, as implemented by Microsoft, is a purely compile-time > transformation. Although Oracle now directs Java, it will probably > take a long, long time for compiler support for database queries to be > added to Java, if ever. > > So the most practical way to add support LINQ-style queries to Java > within the next 5 years would be through classloader tricks or other > bytecode rewriting techniques. Unfortunately, using asSam() for lambda > expressions causes problems for this bytecode rewriting. I think that implementing LINQ with bytecode analysis is the wrong approach, for two reasons: - One the most important features of LINQ is the integration in the host language's syntax. Without that, you don't have a query DSL anymore, just a clever API. To have that feature, compile-time support is needed, and once you modify the compiler, there's no reason to do bytecode analysis anymore. - If closures will be added to the Java language specification, only their syntax and semantics will be specified - not their implementation. So basing bytecode analysis on the fact that the Sun JVM will implement closures a certain way will likely make "LINQ" work only on JVMs that implement closures the same way as Sun. You cannot forbid other implementations to use asSam(). Just my .02? Regards, Alessio From mingyeeiu+lambda at gmail.com Mon May 31 04:44:38 2010 From: mingyeeiu+lambda at gmail.com (Ming-Yee Iu) Date: Mon, 31 May 2010 13:44:38 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: > I think that implementing LINQ with bytecode analysis is the wrong > approach, for two reasons: > > - One the most important features of LINQ is the integration in the > host language's syntax. Without that, you don't have a query DSL > anymore, just a clever API. To have that feature, compile-time support > is needed, and once you modify the compiler, there's no reason to do > bytecode analysis anymore. Again, I will reiterate that I am not trying to convince people about the benefits of LINQ, database queries in Java, or of metaprogramming in Java--those are different debates. Feedback was requested on different translation proposals. My feedback is that a translation scheme that involves doing things at runtime with magic, opaque objects may save on static footprint, but there are additional trade-offs that should be considered, including a) doing things at runtime makes static analysis of bytecode harder. You cannot determine who implements a certain interface with a quick scan of the class hierarchy, for example b) opaque, runtime-generated wrapper objects can hide useful runtime information. For example, some functional frameworks will cache the result of a computation and reuse it if they asked to do processing with the same function. Opaque wrapper objects hide this sort of information. (I understand that theoretically, a framework should not try to peek into the functions that are passed to it, but in reality, things like the instanceof operator still get a lot of use in Java.) > - If closures will be added to the Java language specification, only > their syntax and semantics will be specified - not their > implementation. So basing bytecode analysis on the fact that the Sun > JVM will implement closures a certain way will likely make "LINQ" work > only on JVMs that implement closures the same way as Sun. You cannot > forbid other implementations to use asSam(). This sort of stuff already happens a lot in J2EE and elsewhere. From abies at adres.pl Mon May 31 08:14:43 2010 From: abies at adres.pl (Artur Biesiadowski) Date: Mon, 31 May 2010 17:14:43 +0200 Subject: Translation Using asSam() and LINQ for Java In-Reply-To: References: Message-ID: <4C03D263.8070906@adres.pl> On 31/05/2010 13:44, Ming-Yee Iu wrote: > a) doing things at runtime makes static analysis of bytecode harder. > You cannot determine who implements a certain interface with a quick > scan of the class hierarchy, for example > Isn't the same situation happening today with java.lang.reflect.Proxy? It can be instantiated with Class.forName, with string retrieved from property file/spring configuration. How your 'static analysis' handles that case ? Regards, Artur Biesiadowski