From mike.duigou at oracle.com Tue May 1 14:40:43 2012 From: mike.duigou at oracle.com (mike.duigou at oracle.com) Date: Tue, 01 May 2012 21:40:43 +0000 Subject: hg: lambda/lambda/jdk: update tests for new naming of left() -> inputs() and right() -> values() Message-ID: <20120501214101.AB672470C7@hg.openjdk.java.net> Changeset: 6d2ad6682d99 Author: mduigou Date: 2012-05-01 14:40 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/6d2ad6682d99 update tests for new naming of left() -> inputs() and right() -> values() ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java From mike.duigou at oracle.com Tue May 1 15:07:09 2012 From: mike.duigou at oracle.com (mike.duigou at oracle.com) Date: Tue, 01 May 2012 22:07:09 +0000 Subject: hg: lambda/lambda/jdk: more renaming Message-ID: <20120501220727.D625A470C8@hg.openjdk.java.net> Changeset: 9c1ffc411ff5 Author: mduigou Date: 2012-05-01 15:06 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/9c1ffc411ff5 more renaming ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java From mike.duigou at oracle.com Tue May 1 16:43:57 2012 From: mike.duigou at oracle.com (mike.duigou at oracle.com) Date: Tue, 01 May 2012 23:43:57 +0000 Subject: hg: lambda/lambda/jdk: more renaming related to MapStream Message-ID: <20120501234415.88EA5470CB@hg.openjdk.java.net> Changeset: 4887a040084c Author: mduigou Date: 2012-05-01 16:43 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/4887a040084c more renaming related to MapStream Adds MapStream.swap() for swapping keys and values. Adds (very basic) implementation and tests for groupBy and GroupByMulti (missing test due to generics disaster) ! src/share/classes/java/lang/BiVal.java ! src/share/classes/java/lang/BiValue.java ! src/share/classes/java/lang/Iterable.java ! src/share/classes/java/lang/MapStream.java ! src/share/classes/java/util/Enumeration.java ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java From stuart.marks at oracle.com Tue May 1 17:28:50 2012 From: stuart.marks at oracle.com (stuart.marks at oracle.com) Date: Wed, 02 May 2012 00:28:50 +0000 Subject: hg: lambda/lambda/jdk: Add String.splitAsStream(). Message-ID: <20120502002900.A9751470CD@hg.openjdk.java.net> Changeset: 08b1840dd694 Author: smarks Date: 2012-05-01 17:09 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08b1840dd694 Add String.splitAsStream(). ! src/share/classes/java/lang/String.java + test-ng/tests/org/openjdk/tests/java/lang/StringTest.java From forax at univ-mlv.fr Tue May 1 18:18:46 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 02 May 2012 03:18:46 +0200 Subject: hg: lambda/lambda/jdk: Add String.splitAsStream(). In-Reply-To: <20120502002900.A9751470CD@hg.openjdk.java.net> References: <20120502002900.A9751470CD@hg.openjdk.java.net> Message-ID: <4FA08B76.5090700@univ-mlv.fr> On 05/02/2012 02:28 AM, stuart.marks at oracle.com wrote: > Changeset: 08b1840dd694 > Author: smarks > Date: 2012-05-01 17:09 -0700 > URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08b1840dd694 > > Add String.splitAsStream(). > > ! src/share/classes/java/lang/String.java > + test-ng/tests/org/openjdk/tests/java/lang/StringTest.java > > I think these methods should be added to CharSequence. R?mi From forax at univ-mlv.fr Tue May 1 18:28:25 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 02 May 2012 03:28:25 +0200 Subject: hg: lambda/lambda/jdk: more renaming related to MapStream In-Reply-To: <20120501234415.88EA5470CB@hg.openjdk.java.net> References: <20120501234415.88EA5470CB@hg.openjdk.java.net> Message-ID: <4FA08DB9.7040307@univ-mlv.fr> On 05/02/2012 01:43 AM, mike.duigou at oracle.com wrote: > Changeset: 4887a040084c > Author: mduigou > Date: 2012-05-01 16:43 -0700 > URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/4887a040084c > > more renaming related to MapStream > > Adds MapStream.swap() for swapping keys and values. > > Adds (very basic) implementation and tests for groupBy and GroupByMulti (missing test due to generics disaster) > > ! src/share/classes/java/lang/BiVal.java > ! src/share/classes/java/lang/BiValue.java > ! src/share/classes/java/lang/Iterable.java > ! src/share/classes/java/lang/MapStream.java > ! src/share/classes/java/util/Enumeration.java > ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java > > swap should be: @Override public Iterator> iterator() { return new Iterator>() { final Iterator> source = MapStream.this.asIterable().iterator(); @Override public boolean hasNext() { return source.hasNext(); } @Override public BiValue next() { final BiValue unmapped = source.next(); return new BiValue() { @Override public K getKey() { return unmapped.getValue(); } @Override public K getValue() { return unmapped.getKey(); } //+ equals and hashcode (and serialization ??) // note that if we use Map.Entry instead of BiValue // partial implementations of Entry already exist // in AbstractMap. }; } }; } R?mi From stuart.marks at oracle.com Tue May 1 18:30:52 2012 From: stuart.marks at oracle.com (stuart.marks at oracle.com) Date: Wed, 02 May 2012 01:30:52 +0000 Subject: hg: lambda/lambda/jdk: Minor improvement to CharSequence.CodePointIterable. Message-ID: <20120502013102.C8E4E470D7@hg.openjdk.java.net> Changeset: 8310b83837de Author: smarks Date: 2012-05-01 18:32 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/8310b83837de Minor improvement to CharSequence.CodePointIterable. ! src/share/classes/java/lang/CharSequence.java From henri.gomez at gmail.com Wed May 2 06:27:27 2012 From: henri.gomez at gmail.com (Henri Gomez) Date: Wed, 2 May 2012 15:27:27 +0200 Subject: lambda and debug info failure at typeArrayOop.hpp Message-ID: /usr/bin/sed -e "s/@@ID@@//g" -e "s/@@NAME@@/OpenJDK 8/g" -e "s/@@INFO@@/OpenJDK (1.8.0)/g" -e "s/@@PLATFORM_VERSION@@/1.8/g" -e "s/@@VERSION@@/1.8.0/g" -e "s/@@VENDOR@@/openjdk-osx-build project/g" < /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/jdk/src/macosx/bundle/JDK-Info.plist > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/../macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/Info.plist I tried to build and package latest lambda with debug info activated (fastdebug) but it failed at test time with assert typeArrayOop.hpp:105 /usr/bin/SetFile -a B /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/../macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/../ >>>Finished making images @ Wed May 2 15:02:32 CEST 2012 ... ######################################################################## ##### Leaving jdk for target(s) sanity all images ##### ######################################################################## ##### Build time 00:20:06 jdk for target(s) sanity all images ##### ######################################################################## -- Build times ---------- Target fastdebug_build Start 2012-05-02 14:31:26 End 2012-05-02 15:02:32 00:03:00 corba 00:05:23 hotspot 00:00:38 jaxp 00:00:50 jaxws 00:20:06 jdk 00:01:08 langtools 00:31:06 TOTAL ------------------------- testing build: /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/Home/bin/java -version # To suppress the following error report, specify this argument # after -XX: or in .hotspotrc: SuppressErrorAt=/typeArrayOop.hpp:105 # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (/Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hotspot/src/share/vm/oops/typeArrayOop.hpp:105), pid=93887, tid=7171 # assert(is_within_bounds(which)) failed: index out of bounds # # JRE version: 8.0 # Java VM: OpenJDK 64-Bit Server VM (24.0-b07-fastdebug mixed mode bsd-amd64 compressed oops) # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # An error report file with more information is saved as: # /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hs_err_pid93887.log # # If you would like to submit a bug report, please visit: # http://bugreport.sun.com/bugreport/crash.jsp --- # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (/Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hotspot/src/share/vm/oops/typeArrayOop.hpp:105), pid=93887, tid=7171 # assert(is_within_bounds(which)) failed: index out of bounds # # JRE version: 8.0 # Java VM: OpenJDK 64-Bit Server VM (24.0-b07-fastdebug mixed mode bsd-amd64 compressed oops) # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # If you would like to submit a bug report, please visit: # http://bugreport.sun.com/bugreport/crash.jsp # --------------- T H R E A D --------------- Current thread (0x00007fd613000800): JavaThread "Unknown thread" [_thread_in_vm, id=7171, stack(0x0000000110859000,0x0000000110959000)] Stack: [0x0000000110859000,0x0000000110959000], sp=0x0000000110951700, free space=993k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.dylib+0x6fd9f4] V [libjvm.dylib+0x2a071b] V [libjvm.dylib+0x2f340e] V [libjvm.dylib+0x356bfa] V [libjvm.dylib+0x356cd8] V [libjvm.dylib+0x356fe1] V [libjvm.dylib+0x2a991a] V [libjvm.dylib+0x2a862f] V [libjvm.dylib+0x21c7e9] V [libjvm.dylib+0x21f220] V [libjvm.dylib+0x68d231] V [libjvm.dylib+0x68cba3] V [libjvm.dylib+0x68d727] V [libjvm.dylib+0x68daeb] V [libjvm.dylib+0x68dbcd] V [libjvm.dylib+0x68dcb0] V [libjvm.dylib+0x68dd6c] V [libjvm.dylib+0x6d26f0] V [libjvm.dylib+0x6d314b] V [libjvm.dylib+0x385e90] V [libjvm.dylib+0x6bd3b4] V [libjvm.dylib+0x410482] C [java+0x2a35] JavaMain+0x134 C [libsystem_c.dylib+0x4e8bf] _pthread_start+0x14f C [libsystem_c.dylib+0x51b75] thread_start+0xd Nobody else encounter this assert failure ? From stuart.marks at oracle.com Wed May 2 13:54:48 2012 From: stuart.marks at oracle.com (Stuart Marks) Date: Wed, 02 May 2012 13:54:48 -0700 Subject: hg: lambda/lambda/jdk: Add String.splitAsStream(). In-Reply-To: <4FA08B76.5090700@univ-mlv.fr> References: <20120502002900.A9751470CD@hg.openjdk.java.net> <4FA08B76.5090700@univ-mlv.fr> Message-ID: <4FA19F18.8010409@oracle.com> On 5/1/12 6:18 PM, R?mi Forax wrote: > On 05/02/2012 02:28 AM, stuart.marks at oracle.com wrote: >> Changeset: 08b1840dd694 >> Author: smarks >> Date: 2012-05-01 17:09 -0700 >> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08b1840dd694 >> >> Add String.splitAsStream(). > > I think these methods should be added to CharSequence. Interesting. Seems like Pattern should have splitAsStream() methods added, and then the default implementations in CharSequence could delegate to those. For completeness maybe we should think about providing array-returning split() methods on CharSequence. And other extension methods too ... ? s'marks From stuart.marks at oracle.com Wed May 2 14:28:01 2012 From: stuart.marks at oracle.com (Stuart Marks) Date: Wed, 02 May 2012 14:28:01 -0700 Subject: hg: lambda/lambda/jdk: Modify Iterables.uniqueElements to be fully lazy. In-Reply-To: <4F88B2DC.4030700@univ-mlv.fr> References: <20120413222344.16DCE470B3@hg.openjdk.java.net> <4F88B2DC.4030700@univ-mlv.fr> Message-ID: <4FA1A6E1.6050302@oracle.com> On 4/13/12 4:12 PM, R?mi Forax wrote: > On 04/14/2012 12:23 AM, stuart.marks at oracle.com wrote: >> Changeset: 08c12c22393c >> Author: smarks >> Date: 2012-04-13 15:24 -0700 >> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08c12c22393c >> >> Modify Iterables.uniqueElements to be fully lazy. > > Hi Stuart, > null should be an allowed value. > It's really easy to implement it with a null object. > Also I think it's better to let the user choose which Set he wants to use > (the equals semantics is not always the best). > > So the code should be something like this: [...] Hi, finally getting back to this. From Brian's other notes you might have gathered that we're generally leaning against supporting null values. But it's good to know that using the null object technique can be used to implement it if we choose to do so. Good point also about allowing the caller to choose a different set implementation. The most obvious alternative would be IdentityHashSet which -- doh! -- doesn't exist in the JDK, but which has been implemented elsewhere several times. Mike Duigou also pointed out that if the stream is known to be sorted, maintaining a set isn't necessary at all. Another alternative is to have the caller pass in a Factory instead of an instance. I'll add this to our issues list but I don't think I'll proceed with this at the moment. s'marks From forax at univ-mlv.fr Wed May 2 15:25:50 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Thu, 03 May 2012 00:25:50 +0200 Subject: hg: lambda/lambda/jdk: Modify Iterables.uniqueElements to be fully lazy. In-Reply-To: <4FA1A6E1.6050302@oracle.com> References: <20120413222344.16DCE470B3@hg.openjdk.java.net> <4F88B2DC.4030700@univ-mlv.fr> <4FA1A6E1.6050302@oracle.com> Message-ID: <4FA1B46E.8020703@univ-mlv.fr> On 05/02/2012 11:28 PM, Stuart Marks wrote: > On 4/13/12 4:12 PM, R?mi Forax wrote: >> On 04/14/2012 12:23 AM, stuart.marks at oracle.com wrote: >>> Changeset: 08c12c22393c >>> Author: smarks >>> Date: 2012-04-13 15:24 -0700 >>> URL: >>> http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08c12c22393c >>> >>> Modify Iterables.uniqueElements to be fully lazy. >> >> Hi Stuart, >> null should be an allowed value. >> It's really easy to implement it with a null object. >> Also I think it's better to let the user choose which Set he wants to >> use >> (the equals semantics is not always the best). >> >> So the code should be something like this: [...] > > Hi, finally getting back to this. > > From Brian's other notes you might have gathered that we're generally > leaning against supporting null values. But it's good to know that > using the null object technique can be used to implement it if we > choose to do so. and I feel it's a really bad idea to not support null. I mean we should just propagate the null not do more, not do less. If we don't support null, people can't replace their old code in a library by a code that use lambdas without introducing backward compatibility issue so no refactoring, no way to simplify the code to make it readable. > > Good point also about allowing the caller to choose a different set > implementation. The most obvious alternative would be IdentityHashSet > which -- doh! -- doesn't exist in the JDK, but which has been > implemented elsewhere several times. It exists but you have to cast the spell correctly :) Collections.newSetFromMap(new IdentityHashMap()); > Mike Duigou also pointed out that if the stream is known to be sorted, > maintaining a set isn't necessary at all. I'm not a big fan of attributes that internally say if the stream is sorted or not. It's not in the spirit of the actual collection API. Collection and Set have the same external interface (in OO way) but are two different interfaces and not an interface with a flag that says if the Collection is a set or not. > Another alternative is to have the caller pass in a Factory instead of > an instance. Yes, this is basically what Scala does. > > I'll add this to our issues list but I don't think I'll proceed with > this at the moment. > > s'marks > cheers, R?mi From stuart.marks at oracle.com Fri May 4 15:51:13 2012 From: stuart.marks at oracle.com (stuart.marks at oracle.com) Date: Fri, 04 May 2012 22:51:13 +0000 Subject: hg: lambda/lambda/jdk: AbstractStringBuilder: implement Fillable Message-ID: <20120504225135.E206647163@hg.openjdk.java.net> Changeset: e12990f79b69 Author: smarks Date: 2012-05-04 15:52 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/e12990f79b69 AbstractStringBuilder: implement Fillable ! src/share/classes/java/lang/AbstractStringBuilder.java + test-ng/tests/org/openjdk/tests/java/util/FillableStringTest.java From fsarradin at gmail.com Sat May 5 06:02:30 2012 From: fsarradin at gmail.com (=?ISO-8859-1?Q?Fran=E7ois_Sarradin?=) Date: Sat, 5 May 2012 15:02:30 +0200 Subject: Question about MapStream.intoMulti Message-ID: Hi all, I would like to know what is the purpose of the method MapStream.intoMulti? Is it convert a MapStream into a Map of Collection[s] ? Here is an example that I have tried with this method: public static Map> distribute(Iterable persons) { return persons .groupBy(Age::getDevelopmentStage) .intoMulti( new HashMap>(), () -> new ArrayList()); } But this code generates this error: error: method intoMulti in interface MapStream cannot be applied to given types; required: A,Factory found: HashMap>,lambda reason: invalid inferred types for A,C reason: inferred type does not conform to declared bound(s) inferred: HashMap> bound(s): Map> where A,C,V,K are type-variables: A extends Map declared in method intoMulti(A,Factory) C extends Collection declared in method intoMulti(A,Factory) V extends Object declared in interface MapStream K extends Object declared in interface MapStream Am I wrong ? Why the lambda expression is not inferred into Factory> ? Thanks, Francois Sarradin From forax at univ-mlv.fr Sat May 5 06:53:12 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sat, 05 May 2012 15:53:12 +0200 Subject: Question about MapStream.intoMulti In-Reply-To: References: Message-ID: <4FA530C8.8030108@univ-mlv.fr> I think it's a bug in the signature of intoMulti, instead of ,C extends Collection> A intoMulti(A destination, Factory factory) it should be ,C extends Collection> A intoMulti(A destination, Factory factory) R?mi On 05/05/2012 03:02 PM, Fran?ois Sarradin wrote: > Hi all, > > I would like to know what is the purpose of the method MapStream.intoMulti? > Is it convert a MapStream into a Map of Collection[s] ? > > Here is an example that I have tried with this method: > > public static Map> > distribute(Iterable persons) { > return persons > .groupBy(Age::getDevelopmentStage) > .intoMulti( > new HashMap Collection>(), > () -> new ArrayList()); > } > > But this code generates this error: > > error: method intoMulti in interface MapStream cannot be applied to > given types; > required: A,Factory > found: HashMap>,lambda > reason: invalid inferred types for A,C > reason: inferred type does not conform to declared bound(s) > inferred: HashMap> > bound(s): Map> > where A,C,V,K are type-variables: > A extends Map declared in method > intoMulti(A,Factory) > C extends Collection declared in method > intoMulti(A,Factory) > V extends Object declared in interface MapStream > K extends Object declared in interface MapStream > > Am I wrong ? Why the lambda expression is not inferred into > Factory> ? > > Thanks, > > Francois Sarradin > From brian.goetz at oracle.com Sat May 5 10:05:17 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 5 May 2012 10:05:17 -0700 Subject: Question about MapStream.intoMulti In-Reply-To: References: Message-ID: <04B4105C-F2BC-4FDA-9E32-8472E7EB3FDB@oracle.com> This one is a leftover from when we had a separate stream shape for multimap. Now you can simulate this with mapStream.mapValues(v -> singletonList(v)) Sent from my iPhone On May 5, 2012, at 6:02 AM, Fran?ois Sarradin wrote: > Hi all, > > I would like to know what is the purpose of the method MapStream.intoMulti? > Is it convert a MapStream into a Map of Collection[s] ? > > Here is an example that I have tried with this method: > > public static Map> > distribute(Iterable persons) { > return persons > .groupBy(Age::getDevelopmentStage) > .intoMulti( > new HashMap Collection>(), > () -> new ArrayList()); > } > > But this code generates this error: > > error: method intoMulti in interface MapStream cannot be applied to > given types; > required: A,Factory > found: HashMap>,lambda > reason: invalid inferred types for A,C > reason: inferred type does not conform to declared bound(s) > inferred: HashMap> > bound(s): Map> > where A,C,V,K are type-variables: > A extends Map declared in method > intoMulti(A,Factory) > C extends Collection declared in method > intoMulti(A,Factory) > V extends Object declared in interface MapStream > K extends Object declared in interface MapStream > > Am I wrong ? Why the lambda expression is not inferred into > Factory> ? > > Thanks, > > Francois Sarradin > From fsarradin at gmail.com Sun May 6 02:07:20 2012 From: fsarradin at gmail.com (=?ISO-8859-1?Q?Fran=E7ois_Sarradin?=) Date: Sun, 6 May 2012 11:07:20 +0200 Subject: Question about MapStream.intoMulti In-Reply-To: <04B4105C-F2BC-4FDA-9E32-8472E7EB3FDB@oracle.com> References: <04B4105C-F2BC-4FDA-9E32-8472E7EB3FDB@oracle.com> Message-ID: Thank for your answers. At present, I suppose it is better to play with MapStream only and not to try to convert them into Map. Unless by doing it "by hand"? Regards, Francois Sarradin 2012/5/5 Brian Goetz > This one is a leftover from when we had a separate stream shape for > multimap. Now you can simulate this with > > mapStream.mapValues(v -> singletonList(v)) > > Sent from my iPhone > > On May 5, 2012, at 6:02 AM, Fran?ois Sarradin wrote: > > > Hi all, > > > > I would like to know what is the purpose of the method > MapStream.intoMulti? > > Is it convert a MapStream into a Map of Collection[s] ? > > > > Here is an example that I have tried with this method: > > > > public static Map> > > distribute(Iterable persons) { > > return persons > > .groupBy(Age::getDevelopmentStage) > > .intoMulti( > > new HashMap > Collection>(), > > () -> new ArrayList()); > > } > > > > But this code generates this error: > > > > error: method intoMulti in interface MapStream cannot be applied to > > given types; > > required: A,Factory > > found: HashMap>,lambda > > reason: invalid inferred types for A,C > > reason: inferred type does not conform to declared bound(s) > > inferred: HashMap> > > bound(s): Map> > > where A,C,V,K are type-variables: > > A extends Map declared in method > > intoMulti(A,Factory) > > C extends Collection declared in method > > intoMulti(A,Factory) > > V extends Object declared in interface MapStream > > K extends Object declared in interface MapStream > > > > Am I wrong ? Why the lambda expression is not inferred into > > Factory> ? > > > > Thanks, > > > > Francois Sarradin > > > From mike.duigou at oracle.com Sun May 6 08:53:34 2012 From: mike.duigou at oracle.com (mike.duigou at oracle.com) Date: Sun, 06 May 2012 15:53:34 +0000 Subject: hg: lambda/lambda/jdk: 2 new changesets Message-ID: <20120506155433.A13C74717B@hg.openjdk.java.net> Changeset: 161ec859b1ac Author: mduigou Date: 2012-05-06 08:51 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/161ec859b1ac better asMultiMap implementation better swap implementation remove superfluous ? extends from asIterable test improvements ! src/share/classes/java/lang/Iterable.java ! src/share/classes/java/lang/MapStream.java ! src/share/classes/java/util/Enumeration.java ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java Changeset: 87f534619b92 Author: mduigou Date: 2012-05-06 08:53 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/87f534619b92 Merge From peter.levart at gmail.com Sun May 6 15:25:49 2012 From: peter.levart at gmail.com (Peter Levart) Date: Mon, 07 May 2012 00:25:49 +0200 Subject: Initial prototype for BiStream (renamed to MapStream) In-Reply-To: References: <4F987C5C.8060107@univ-mlv.fr> Message-ID: <3269095.f9xYSJlWzg@cube> Hi Mike, Brian, I have experimented with a thechique that uses "push" instead of "pull" (like Iterable or MapStream). Here's the result: https://github.com/plevart/PushPipes Pipe is a pair to Iterable BiPipe is a pair to MapStream I tried to implement most of the operations present in Iterable and MapStream. There are pros and cons to this approach. Pros: - No box/unbox-ing of intermediate results (BiValue-s) - The code for various operations seems to be much simpler Con: - References in the chain of operations are in direction parent -> child (as opposed to child -> parent with pull approach of Iterator/MapStream), so each parent can only have one child (you can not re-use half built chain to build two different continuations). What dou you think? Regards, Peter On Wednesday, April 25, 2012 05:33:31 PM Mike Duigou wrote: > Or, if you are the type of person who likes to be their explanations to be > entertaining: > > http://youtu.be/wbp-3BJWsU8?t=10m20s > > which was bug: > > http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706? > > Mike > > On Apr 25 2012, at 15:36 , R?mi Forax wrote: > > Hi Peter, > > The original implementation of IdentityHashMap was based on the same > > idea, reusing Map.Entry implementation, and it didn't work well. > > > > Full story here: > > http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6232484 > > > > R?mi > > > > On 04/26/2012 12:25 AM, Peter Levart wrote: > >> On Wednesday, April 18, 2012 03:39:28 PM Mike Duigou wrote: > >>> There's a big question lurking in the implementation involving > >>> boxing/unboxing of BiValue as used by the BiBlock, BiMapper and > >>> Predicate. > >> > >> I don't know if this is a good idea, but pragmatic approach could be to > >> re-use the intermediate BiValues and control manually if you need > >> BiValue(s) by reference or just momentarily for extracting the > >> components (i.e. whether the reference to BiValue "escapes" the > >> iteration step or not). > >> > >> For example: > >> > >> public abstract class BiValueStream implements Iterable >> U>> { > >> > >> private boolean reuseResult = true; > >> > >> private static class BiVal implements BiValue > >> { > >> > >> private T left; > >> private U right; > >> > >> @Override > >> public T left() > >> { > >> > >> return left; > >> > >> } > >> > >> @Override > >> public U right() > >> { > >> > >> return right; > >> > >> } > >> > >> } > >> > >> BiValueStream map(final BiMapper mapper) > >> { > >> > >> return new BiValueStream() > >> { > >> > >> @Override > >> public Iterator> iterator() > >> { > >> > >> final Iterator> source = > >> BiValueStream.this.iterator(); > >> > >> return new Iterator>() > >> { > >> > >> @Override > >> public boolean hasNext() > >> { > >> > >> return source.hasNext(); > >> > >> } > >> > >> private BiVal reusableResult = reuseResult ? new > >> BiVal() : null; > >> > >> @Override > >> public BiValue next() > >> { > >> > >> BiValue next = source.next(); > >> BiVal result = reuseResult ? reusableResult : > >> new BiVal(); > >> result.left = next.left(); > >> result.right = mapper.map(next.left(), next.right()); > >> return result; > >> > >> } > >> > >> }; > >> > >> } > >> > >> }; > >> > >> } > >> > >> public BiValueStream reuseResult(boolean reuseResult) > >> { > >> > >> this.reuseResult = reuseResult; > >> return this; > >> > >> } > >> > >> } > >> > >> > >> // an example where BiVal is resused: > >> > >> BiValueStream keyVals = ...; > >> Map keyValLengths = new HashMap<>(); > >> > >> for (BiValue keyValLength : keyVals.map((key, val) -> > >> key.length() + val.length())) { > >> > >> keyValLengths.put(keyValLength.left(), keyValLength.right()); > >> > >> } > >> > >> // and where it is not: > >> > >> List> keyValLengthList = new ArrayList<>(); > >> > >> for (BiValue keyValLength : keyVals.map((key, val) -> > >> key.length() + val.length()).reuseResult(false)) { > >> > >> keyValLengthList.add(keyValLength); > >> > >> } > >> > >> > >> ...usually, when you chain transformations, you don't need intermediate > >> BiValues by reference, just the components. Only at the end you may need > >> them. > >> > >> > >> Regards, > >> Peter From henri.gomez at gmail.com Sun May 6 23:33:37 2012 From: henri.gomez at gmail.com (Henri Gomez) Date: Mon, 7 May 2012 08:33:37 +0200 Subject: hg: lambda/lambda/jdk: 2 new changesets In-Reply-To: <20120506155433.A13C74717B@hg.openjdk.java.net> References: <20120506155433.A13C74717B@hg.openjdk.java.net> Message-ID: Build failed for me : ../../../src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java:2476: error: SubMap is not abstract and does not override abstract method asIterable() in MapStream static final class SubMap extends AbstractMap ^ where K,V are type-variables: K extends Object declared in class SubMap V extends Object declared in class SubMap ../../../src/solaris/classes/java/lang/ProcessEnvironment.java:221: error: StringEnvironment is not abstract and does not override abstract method asIterable() in MapStream private static class StringEnvironment ^ /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:367: error: Aliases is not abstract and does not override abstract method asIterable() in MapStream private static final class Aliases ^ /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:596: error: Classes is not abstract and does not override abstract method asIterable() in MapStream private static final class Classes ^ /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:653: error: Cache is not abstract and does not override abstract method asIterable() in MapStream private static final class Cache ^ /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/jdk/src/share/classes/java/text/AttributedString.java:1043: error: AttributedString.AttributeMap is not abstract and does not override abstract method asIterable() in MapStream final private class AttributeMap extends AbstractMap { ^ Note: Some input files use or override a deprecated API. Note: Recompile with -Xlint:deprecation for details. Note: Some input files use unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 29 errors make[4]: *** [.compile.classlist] Error 1 make[3]: *** [all] Error 1 make[2]: *** [all] Error 1 make[1]: *** [jdk-build] Error 2 Did you notice same error ? 2012/5/6 : > Changeset: 161ec859b1ac > Author: ? ?mduigou > Date: ? ? ?2012-05-06 08:51 -0700 > URL: ? ? ? http://hg.openjdk.java.net/lambda/lambda/jdk/rev/161ec859b1ac > > better asMultiMap implementation > better swap implementation > remove superfluous ? extends from asIterable > > test improvements > > ! src/share/classes/java/lang/Iterable.java > ! src/share/classes/java/lang/MapStream.java > ! src/share/classes/java/util/Enumeration.java > ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java > > Changeset: 87f534619b92 > Author: ? ?mduigou > Date: ? ? ?2012-05-06 08:53 -0700 > URL: ? ? ? http://hg.openjdk.java.net/lambda/lambda/jdk/rev/87f534619b92 > > Merge > > > From mike.duigou at oracle.com Mon May 7 00:09:56 2012 From: mike.duigou at oracle.com (Mike Duigou) Date: Mon, 7 May 2012 00:09:56 -0700 Subject: hg: lambda/lambda/jdk: 2 new changesets In-Reply-To: References: <20120506155433.A13C74717B@hg.openjdk.java.net> Message-ID: <5D26062C-A30B-4829-A3F9-0B8FD26B7039@oracle.com> I only did an incremental rebuild before committing which did work. I will do a clean build and figure out what needs to be corrected. Mike On May 6 2012, at 23:33 , Henri Gomez wrote: > Build failed for me : > > ../../../src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java:2476: > error: SubMap is not abstract and does not override abstract method > asIterable() in MapStream > static final class SubMap extends AbstractMap > ^ > where K,V are type-variables: > K extends Object declared in class SubMap > V extends Object declared in class SubMap > ../../../src/solaris/classes/java/lang/ProcessEnvironment.java:221: > error: StringEnvironment is not abstract and does not override > abstract method asIterable() in MapStream > private static class StringEnvironment > ^ > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:367: > error: Aliases is not abstract and does not override abstract method > asIterable() in MapStream > private static final class Aliases > ^ > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:596: > error: Classes is not abstract and does not override abstract method > asIterable() in MapStream > private static final class Classes > ^ > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:653: > error: Cache is not abstract and does not override abstract method > asIterable() in MapStream > private static final class Cache > ^ > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/jdk/src/share/classes/java/text/AttributedString.java:1043: > error: AttributedString.AttributeMap is not abstract and does not > override abstract method asIterable() in MapStream > final private class AttributeMap extends AbstractMap { > ^ > Note: Some input files use or override a deprecated API. > Note: Recompile with -Xlint:deprecation for details. > Note: Some input files use unchecked or unsafe operations. > Note: Recompile with -Xlint:unchecked for details. > 29 errors > make[4]: *** [.compile.classlist] Error 1 > make[3]: *** [all] Error 1 > make[2]: *** [all] Error 1 > make[1]: *** [jdk-build] Error 2 > > Did you notice same error ? > > > 2012/5/6 : >> Changeset: 161ec859b1ac >> Author: mduigou >> Date: 2012-05-06 08:51 -0700 >> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/161ec859b1ac >> >> better asMultiMap implementation >> better swap implementation >> remove superfluous ? extends from asIterable >> >> test improvements >> >> ! src/share/classes/java/lang/Iterable.java >> ! src/share/classes/java/lang/MapStream.java >> ! src/share/classes/java/util/Enumeration.java >> ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java >> >> Changeset: 87f534619b92 >> Author: mduigou >> Date: 2012-05-06 08:53 -0700 >> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/87f534619b92 >> >> Merge >> >> >> From forax at univ-mlv.fr Mon May 7 00:32:34 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Mon, 07 May 2012 09:32:34 +0200 Subject: hg: lambda/lambda/jdk: 2 new changesets In-Reply-To: <5D26062C-A30B-4829-A3F9-0B8FD26B7039@oracle.com> References: <20120506155433.A13C74717B@hg.openjdk.java.net> <5D26062C-A30B-4829-A3F9-0B8FD26B7039@oracle.com> Message-ID: <4FA77A92.6010904@univ-mlv.fr> On 05/07/2012 09:09 AM, Mike Duigou wrote: > I only did an incremental rebuild before committing which did work. I will do a clean build and figure out what needs to be corrected. > > Mike It seems that asIterable() is perhaps a name too common. R?mi > > On May 6 2012, at 23:33 , Henri Gomez wrote: > >> Build failed for me : >> >> ../../../src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java:2476: >> error: SubMap is not abstract and does not override abstract method >> asIterable() in MapStream >> static final class SubMap extends AbstractMap >> ^ >> where K,V are type-variables: >> K extends Object declared in class SubMap >> V extends Object declared in class SubMap >> ../../../src/solaris/classes/java/lang/ProcessEnvironment.java:221: >> error: StringEnvironment is not abstract and does not override >> abstract method asIterable() in MapStream >> private static class StringEnvironment >> ^ >> /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:367: >> error: Aliases is not abstract and does not override abstract method >> asIterable() in MapStream >> private static final class Aliases >> ^ >> /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:596: >> error: Classes is not abstract and does not override abstract method >> asIterable() in MapStream >> private static final class Classes >> ^ >> /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/gensrc/sun/nio/cs/StandardCharsets.java:653: >> error: Cache is not abstract and does not override abstract method >> asIterable() in MapStream >> private static final class Cache >> ^ >> /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/jdk/src/share/classes/java/text/AttributedString.java:1043: >> error: AttributedString.AttributeMap is not abstract and does not >> override abstract method asIterable() in MapStream >> final private class AttributeMap extends AbstractMap { >> ^ >> Note: Some input files use or override a deprecated API. >> Note: Recompile with -Xlint:deprecation for details. >> Note: Some input files use unchecked or unsafe operations. >> Note: Recompile with -Xlint:unchecked for details. >> 29 errors >> make[4]: *** [.compile.classlist] Error 1 >> make[3]: *** [all] Error 1 >> make[2]: *** [all] Error 1 >> make[1]: *** [jdk-build] Error 2 >> >> Did you notice same error ? >> >> >> 2012/5/6: >>> Changeset: 161ec859b1ac >>> Author: mduigou >>> Date: 2012-05-06 08:51 -0700 >>> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/161ec859b1ac >>> >>> better asMultiMap implementation >>> better swap implementation >>> remove superfluous ? extends from asIterable >>> >>> test improvements >>> >>> ! src/share/classes/java/lang/Iterable.java >>> ! src/share/classes/java/lang/MapStream.java >>> ! src/share/classes/java/util/Enumeration.java >>> ! test-ng/tests/org/openjdk/tests/java/util/MapStreamTest.java >>> >>> Changeset: 87f534619b92 >>> Author: mduigou >>> Date: 2012-05-06 08:53 -0700 >>> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/87f534619b92 >>> >>> Merge >>> >>> >>> > From mike.duigou at oracle.com Mon May 7 00:49:34 2012 From: mike.duigou at oracle.com (mike.duigou at oracle.com) Date: Mon, 07 May 2012 07:49:34 +0000 Subject: hg: lambda/lambda/jdk: Fix issue with Map.asIterable Message-ID: <20120507074944.85F454718A@hg.openjdk.java.net> Changeset: f03d361fbb79 Author: mduigou Date: 2012-05-07 00:43 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/f03d361fbb79 Fix issue with Map.asIterable ! src/share/classes/java/util/Map.java From henri.gomez at gmail.com Mon May 7 06:55:51 2012 From: henri.gomez at gmail.com (Henri Gomez) Date: Mon, 7 May 2012 15:55:51 +0200 Subject: hg: lambda/lambda/jdk: Fix issue with Map.asIterable In-Reply-To: <20120507074944.85F454718A@hg.openjdk.java.net> References: <20120507074944.85F454718A@hg.openjdk.java.net> Message-ID: Lambda build fixed. http://openjdk-osx-build.googlecode.com/files/OpenJDK-OSX-8-x64-lambda-jdk-b35-20120507.dmg Thanks 2012/5/7 : > Changeset: f03d361fbb79 > Author: ? ?mduigou > Date: ? ? ?2012-05-07 00:43 -0700 > URL: ? ? ? http://hg.openjdk.java.net/lambda/lambda/jdk/rev/f03d361fbb79 > > Fix issue with Map.asIterable > > ! src/share/classes/java/util/Map.java > > From peter.levart at marand.si Tue May 8 01:06:08 2012 From: peter.levart at marand.si (Peter Levart) Date: Tue, 8 May 2012 10:06:08 +0200 Subject: MapStream.map* methods Message-ID: <11349148.NZPPyR3EY2@peterl.marand.si> Hi Mike and others, I'm trying to understand the purpose of the 3 MapStream.map* methods that have the following signatures: public interface MapStream { MapStream map(BiMapper mapper) default ... MapStream mapValues(Mapper mapper) default { return map( (k, v) -> mapper.map(v)); } MapStream> mapValuesMulti( BiMapper> mapper ) default ... ... the first is obvious. It replaces the values in a key/value pairs with values computed by BiMapper from key/value pairs. This is the most common method and for the less common case (to replace keys instead of values) one can use the following idiom: mapStream.swap().map().swap()... ... the second (mapValues) is just a shorthand for the first in the common case when keys are not needed in the computation of values. Now I think that both could have a more forgiving generic signature: MapStream map( BiMapper mapper ); MapStream mapValues(Mapper mapper); ... the third (mapValuesMulti) is the one that I don't see the point in. It is just a more constrained version of plain map(). Even the default implementation bodies are the same. Are those API choices only to help inferencing engine or I'm missing something? What I'm missing is the following method: MapStream flatMap( BiMapper> ); By analogy to the similar method in Iterable it could also be used to flatten (Multi)MapStreams: MapStream> multiMapStream = ...; MapStream flattened = multiMapStream.flatMap((x, ys) -> ys); On the other front, it would be nice to have the following method in MapStream: MapStream> groupByKey(); Regards, Peter From peter.levart at marand.si Tue May 8 01:22:51 2012 From: peter.levart at marand.si (Peter Levart) Date: Tue, 8 May 2012 10:22:51 +0200 Subject: MapStream.sorted In-Reply-To: <11349148.NZPPyR3EY2@peterl.marand.si> References: <11349148.NZPPyR3EY2@peterl.marand.si> Message-ID: <2243221.v9uipbbr40@peterl.marand.si> Hi Mike and others, Sorry to be picky, but the following MapStream method: MapStream sorted(Comparator comparator) default { TreeMap result = new TreeMap<>(comparator); forEach( (k, v) -> { result.put(k, v); } ); return result; } ..."squashes" entries with duplicate keys (those that comparator.compare(k1, k2) returns 0 for)... The analog Iterable.sorted is more correct (uses PriorityQueue). One still might want this behavior, but she could achieve that same by: mapStream.into(new TreeMap<>(comparator)) Regards, Peter From forax at univ-mlv.fr Tue May 8 04:31:33 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Tue, 08 May 2012 13:31:33 +0200 Subject: MapStream.map* methods In-Reply-To: <11349148.NZPPyR3EY2@peterl.marand.si> References: <11349148.NZPPyR3EY2@peterl.marand.si> Message-ID: <4FA90415.9080109@univ-mlv.fr> On 05/08/2012 10:06 AM, Peter Levart wrote: > Hi Mike and others, > > I'm trying to understand the purpose of the 3 MapStream.map* methods that have > the following signatures: > > public interface MapStream { > > MapStream map(BiMapper mapper) default ... > > MapStream mapValues(Mapper mapper) default { > return map( (k, v) -> mapper.map(v)); > } > > MapStream> mapValuesMulti( > BiMapper> mapper > ) default ... > > ... the first is obvious. It replaces the values in a key/value pairs with > values computed by BiMapper from key/value pairs. This is the most common > method and for the less common case (to replace keys instead of values) one > can use the following idiom: > > mapStream.swap().map().swap()... > > ... the second (mapValues) is just a shorthand for the first in the common case > when keys are not needed in the computation of values. I agree. > > Now I think that both could have a more forgiving generic signature: > > MapStream map( > BiMapper mapper > ); > > MapStream mapValues(Mapper mapper); yes ! > > ... the third (mapValuesMulti) is the one that I don't see the point in. It is > just a more constrained version of plain map(). Even the default > implementation bodies are the same. Are those API choices only to help > inferencing engine or I'm missing something? no, map..Multi is here because at some point in the past, there were an interface MultiMap. This should be cleanup. > > What I'm missing is the following method: > > MapStream flatMap( > BiMapper> > ); > > By analogy to the similar method in Iterable it could also be used to flatten > (Multi)MapStreams: > > MapStream> multiMapStream = ...; > > MapStream flattened = multiMapStream.flatMap((x, ys) -> ys); > > > On the other front, it would be nice to have the following method in > MapStream: > > MapStream> groupByKey(); > > > > Regards, > > Peter > > regards, R?mi From brian.goetz at oracle.com Tue May 8 08:07:44 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 8 May 2012 08:07:44 -0700 Subject: MapStream.sorted In-Reply-To: <2243221.v9uipbbr40@peterl.marand.si> References: <11349148.NZPPyR3EY2@peterl.marand.si> <2243221.v9uipbbr40@peterl.marand.si> Message-ID: <9B654BD0-5667-4427-8696-3B73EB78121B@oracle.com> There's a tension between having a single bi-valued stream (as we're trying to do currently, called MapStream) and having two versions, one for streams of key-value pairs (where the key is unique) and one for streams of undifferentiated pairs (such as the result of a zip() operation). Where and how we maintain the "keys are unique" property, what operations preserve that, what operations require that, etc, is still a work in progress. On May 8, 2012, at 1:22 AM, Peter Levart wrote: > Hi Mike and others, > > Sorry to be picky, but the following MapStream method: > > MapStream sorted(Comparator comparator) default { > TreeMap result = new TreeMap<>(comparator); > forEach( (k, v) -> { result.put(k, v); } ); > > return result; > } > > > ..."squashes" entries with duplicate keys (those that comparator.compare(k1, > k2) returns 0 for)... > > The analog Iterable.sorted is more correct (uses PriorityQueue). > > One still might want this behavior, but she could achieve that same by: > > mapStream.into(new TreeMap<>(comparator)) > > > Regards, Peter > > From brian.goetz at oracle.com Tue May 8 08:17:56 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 8 May 2012 08:17:56 -0700 Subject: MapStream.map* methods In-Reply-To: <11349148.NZPPyR3EY2@peterl.marand.si> References: <11349148.NZPPyR3EY2@peterl.marand.si> Message-ID: <73EB9B90-3057-44D7-A664-7355173D38A9@oracle.com> On May 8, 2012, at 1:06 AM, Peter Levart wrote: > Hi Mike and others, > > I'm trying to understand the purpose of the 3 MapStream.map* methods that have > the following signatures: > > public interface MapStream { > > MapStream map(BiMapper mapper) default ... > > MapStream mapValues(Mapper mapper) default { > return map( (k, v) -> mapper.map(v)); > } > > MapStream> mapValuesMulti( > BiMapper> mapper > ) default ... > > ... the first is obvious. It replaces the values in a key/value pairs with > values computed by BiMapper from key/value pairs. This is the most common > method and for the less common case (to replace keys instead of values) one > can use the following idiom: > > mapStream.swap().map().swap()... > > ... the second (mapValues) is just a shorthand for the first in the common case > when keys are not needed in the computation of values. The reason for this shorthand version is that you may have in hand a method that does the mapping already: people.mapped(Person::getBirthday) // stream of (Person, Date) .mapValues(Date::toString) // stream of (Person, String) instead of ...mapValues( (person, birthday) -> birthday.toString()) > On the other front, it would be nice to have the following method in > MapStream: > > MapStream> groupByKey(); Good catch. From keith.mcguigan at oracle.com Tue May 8 13:52:09 2012 From: keith.mcguigan at oracle.com (Keith McGuigan) Date: Tue, 8 May 2012 16:52:09 -0400 Subject: lambda and debug info failure at typeArrayOop.hpp In-Reply-To: References: Message-ID: <731A4D47-397A-40D4-9374-5AFB339258C0@oracle.com> Hi Henri - Sorry for the delay. Can you try applying this patch and see if it fixes it? If it works for you I'll get it into the repo ASAP. diff --git a/src/share/vm/classfile/genericSignatures.cpp b/src/share/vm/classfile/genericSignatures.cpp --- a/src/share/vm/classfile/genericSignatures.cpp +++ b/src/share/vm/classfile/genericSignatures.cpp @@ -431,7 +431,7 @@ int i_length = i_icls->length(); // Find inner_klass attribute - for (int i = 0; i < i_length; i += next_offset) { + for (int i = 0; i + name_offset < i_length; i += next_offset) { int ioff = i_icls->ushort_at(i + inner_index); int ooff = i_icls->ushort_at(i + outer_index); int noff = i_icls->ushort_at(i + name_offset); On May 2, 2012, at 9:27 AM, Henri Gomez wrote: > /usr/bin/sed -e "s/@@ID@@//g" -e "s/@@NAME@@/OpenJDK 8/g" -e > "s/@@INFO@@/OpenJDK (1.8.0)/g" -e "s/@@PLATFORM_VERSION@@/1.8/g" -e > "s/@@VERSION@@/1.8.0/g" -e "s/@@VENDOR@@/openjdk-osx-build project/g" > < /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/jdk/src/macosx/bundle/JDK-Info.plist >> /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/../macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/Info.plist > I tried to build and package latest lambda with debug info activated > (fastdebug) but it failed at test time with assert > typeArrayOop.hpp:105 > > /usr/bin/SetFile -a B > /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64/../macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/../ >>>> Finished making images @ Wed May 2 15:02:32 CEST 2012 ... > ######################################################################## > ##### Leaving jdk for target(s) sanity all images ##### > ######################################################################## > ##### Build time 00:20:06 jdk for target(s) sanity all images ##### > ######################################################################## > > -- Build times ---------- > Target fastdebug_build > Start 2012-05-02 14:31:26 > End 2012-05-02 15:02:32 > 00:03:00 corba > 00:05:23 hotspot > 00:00:38 jaxp > 00:00:50 jaxws > 00:20:06 jdk > 00:01:08 langtools > 00:31:06 TOTAL > ------------------------- > testing build: /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/build/macosx-amd64-fastdebug/j2sdk-bundle/1.8.0.jdk/Contents/Home/bin/java > -version > # To suppress the following error report, specify this argument > # after -XX: or in .hotspotrc: SuppressErrorAt=/typeArrayOop.hpp:105 > # > # A fatal error has been detected by the Java Runtime Environment: > # > # Internal Error > (/Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hotspot/src/share/vm/oops/typeArrayOop.hpp:105), > pid=93887, tid=7171 > # assert(is_within_bounds(which)) failed: index out of bounds > # > # JRE version: 8.0 > # Java VM: OpenJDK 64-Bit Server VM (24.0-b07-fastdebug mixed mode > bsd-amd64 compressed oops) > # Failed to write core dump. Core dumps have been disabled. To enable > core dumping, try "ulimit -c unlimited" before starting Java again > # > # An error report file with more information is saved as: > # /Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hs_err_pid93887.log > # > # If you would like to submit a bug report, please visit: > # http://bugreport.sun.com/bugreport/crash.jsp > > --- > > # > # A fatal error has been detected by the Java Runtime Environment: > # > # Internal Error > (/Users/henri/Documents/jenkins/data/jobs/openjdk-jdk8-lambda/workspace/hotspot/src/share/vm/oops/typeArrayOop.hpp:105), > pid=93887, tid=7171 > # assert(is_within_bounds(which)) failed: index out of bounds > # > # JRE version: 8.0 > # Java VM: OpenJDK 64-Bit Server VM (24.0-b07-fastdebug mixed mode > bsd-amd64 compressed oops) > # Failed to write core dump. Core dumps have been disabled. To enable > core dumping, try "ulimit -c unlimited" before starting Java again > # > # If you would like to submit a bug report, please visit: > # http://bugreport.sun.com/bugreport/crash.jsp > # > > --------------- T H R E A D --------------- > > Current thread (0x00007fd613000800): JavaThread "Unknown thread" > [_thread_in_vm, id=7171, stack(0x0000000110859000,0x0000000110959000)] > > Stack: [0x0000000110859000,0x0000000110959000], > sp=0x0000000110951700, free space=993k > Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) > V [libjvm.dylib+0x6fd9f4] > V [libjvm.dylib+0x2a071b] > V [libjvm.dylib+0x2f340e] > V [libjvm.dylib+0x356bfa] > V [libjvm.dylib+0x356cd8] > V [libjvm.dylib+0x356fe1] > V [libjvm.dylib+0x2a991a] > V [libjvm.dylib+0x2a862f] > V [libjvm.dylib+0x21c7e9] > V [libjvm.dylib+0x21f220] > V [libjvm.dylib+0x68d231] > V [libjvm.dylib+0x68cba3] > V [libjvm.dylib+0x68d727] > V [libjvm.dylib+0x68daeb] > V [libjvm.dylib+0x68dbcd] > V [libjvm.dylib+0x68dcb0] > V [libjvm.dylib+0x68dd6c] > V [libjvm.dylib+0x6d26f0] > V [libjvm.dylib+0x6d314b] > V [libjvm.dylib+0x385e90] > V [libjvm.dylib+0x6bd3b4] > V [libjvm.dylib+0x410482] > C [java+0x2a35] JavaMain+0x134 > C [libsystem_c.dylib+0x4e8bf] _pthread_start+0x14f > C [libsystem_c.dylib+0x51b75] thread_start+0xd > > Nobody else encounter this assert failure ? > From forax at univ-mlv.fr Tue May 8 15:17:39 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Wed, 09 May 2012 00:17:39 +0200 Subject: Reducers - A Library and Model for Collection Processing Message-ID: <4FA99B83.8040100@univ-mlv.fr> An article by Rich Hickey, http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html Hum, the design remember me something :) R?mi From bobfoster at gmail.com Tue May 8 18:48:19 2012 From: bobfoster at gmail.com (Bob Foster) Date: Tue, 8 May 2012 18:48:19 -0700 Subject: Reducers Message-ID: This might be of interest and on topic to the few who haven't already seen it. http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html Bob From robert.field at oracle.com Wed May 9 08:51:52 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Wed, 09 May 2012 15:51:52 +0000 Subject: hg: lambda/lambda/jdk: Implement var-args in method references for non-var-args SAMs. Verify in LambdaMetaFactory. Implemented for inner-class generator. Message-ID: <20120509155220.144A6471EF@hg.openjdk.java.net> Changeset: 8c7b2ba3bab0 Author: Robert Field Date: 2012-05-08 19:39 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/8c7b2ba3bab0 Implement var-args in method references for non-var-args SAMs. Verify in LambdaMetaFactory. Implemented for inner-class generator. ! src/share/classes/java/lang/invoke/InnerClassGenerator.java + src/share/classes/java/lang/invoke/InstructionAdapter.java ! src/share/classes/java/lang/invoke/LambdaMetafactory.java + test-ng/tests/org/openjdk/tests/javac/LambdaTranslationTestVarArgs.java From jim.gish at oracle.com Wed May 9 12:39:32 2012 From: jim.gish at oracle.com (Jim Gish) Date: Wed, 09 May 2012 15:39:32 -0400 Subject: ambiguous type inference while working with primitives In-Reply-To: <4F56A16C.3030306@oracle.com> References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> Message-ID: <4FAAC7F4.3020501@oracle.com> On 03/06/2012 06:44 PM, maurizio cimadamore wrote: > Hi > This error occurs because you have two applicable methods, namely: > > *) comparing(IntMapper) > > *) comparing(LongMapper) > > When there are multiple applicable methods, the compiler tries to > disambiguate the call-site using a routine called most-specific. The > goal is to look at the two ambiguous signatures and see if one can be > considered 'more specific' than the other. For instance, if you have two > applicable methods, one accepting an Object, and the other accepting an > Integer, the latter would 'win' as Integer is a subtype of Object. > > What's happening in this case is that the compiler doesn't have enough > information to disambiguate the call-site by just looking at the method > signatures - that's because IntMapper and LongMapper are two unrelated > types, so the compiler doesn't know which method to pick - hence the > ambiguity error. > > We are currently exploring the design space, to see if we can allow some > restricted form of structural subtyping in the most specific algorithm > (this would allow, i.e. to prefer IntMapper to LongMapper because the > return type of the IntMapper's descriptor is more specific). > > Maurizio > > On 06-Mar-12 8:51 PM, Antoras wrote: >> I get compiler errors due to ambiguous Mapper-objects. I have a class >> Person which has a method getAge(). If the return value of this method >> is 'int' the following inline Mapper-object produces an error: >> >> Comparator c = comparing((Person p1) -> p1.getAge()); >> >> If the return type is 'Integer' the above code works. >> >> This line: >> >> Comparator c = comparing(Person::getAge); >> >> works neither with 'Integer' nor with 'int'; >> >> Is this expected behavior or should the type checker recognize that >> IntMapper is the first one to "choose"? >> >> >> The error message: >> >> ListTest.java:203: error: reference to comparing is ambiguous, both >> methodcomparing(LongMapper) in Comparators and method >> comparing(IntMapper) in Comparators match >> Comparator c = comparing((Person p1) -> p1.getAge()); >> ^ >> where T#1,T#2 are type-variables: >> T#1 extends Object declared in methodcomparing(LongMapper) >> T#2 extends Object declared in methodcomparing(IntMapper) >> > I think I have the same problem here: StringJoinerTest.java:46: error: reference to mapReduce is ambiguous, both method mapReduce(LongMapper,long,LongBinaryOperator) in Iterable and method mapReduce(DoubleMapper,double,DoubleBinaryOperator) in Iterable match int altCompOfStringsLength = lastNames.mapReduce( e -> e.length(), 0, (a, b) -> a+b); ^ where T is a type-variable: T extends Object declared in interface Iterable 1 error So, how does one go about disambiguating this, other than breaking out the lambda expressions (and somewhat defeating the point of the compactness value). This, for example, works: int stringsLength = lastNames.map(e -> e.length()).reduce(0, (a, b) -> a+b); Thanks, Jim From paulo.silveira at caelum.com.br Wed May 9 21:14:11 2012 From: paulo.silveira at caelum.com.br (Paulo Silveira) Date: Thu, 10 May 2012 01:14:11 -0300 Subject: ambiguous type inference while working with primitives In-Reply-To: <4FAAC7F4.3020501@oracle.com> References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> Message-ID: I do have problems with even simpler cases (build 1.8.0-jdk8-b35-20120502): List list = new ArrayList<>(); list.sort(Comparators.comparing(Object::toString)); list.sort(Comparators.comparing((o) -> o.toString())); both examples fail compiling: error: no suitable method found for comparing(member reference) list.sorted(Comparators.comparing(Object::toString)); ^ method Comparators.comparing(DoubleMapper) is not applicable (cyclic inference - cannot infer target type for given lambda/method reference expression) method Comparators.comparing(LongMapper) is not applicable (cyclic inference - cannot infer target type for given lambda/method reference expression) method Comparators.comparing(IntMapper) is not applicable (cyclic inference - cannot infer target type for given lambda/method reference expression) method Comparators.comparing(Mapper) is not applicable (cyclic inference - cannot infer target type for given lambda/method reference expression) where T#1,T#2,T#3,T#4,U are type-variables: T#1 extends Object declared in method comparing(DoubleMapper) T#2 extends Object declared in method comparing(LongMapper) T#3 extends Object declared in method comparing(IntMapper) T#4 extends Object declared in method comparing(Mapper) U extends Comparable declared in method comparing(Mapper) It does not work even if I try to split the statement: Comparator c = Comparators.comparing(Object::toString); The only way to make it work is to be explicit: list.sort(Comparators.comparing(Object::toString)); Going further, couldn't we have an List.sort overload to directly receive a Mapper as parameter? public > void sort(Mapper mapper) default { Collections.sort(this, new MapperComparator(mapper)); } This would make possible to invoke a quite short list.sort(Class::getAttribute); -- Paulo Silveira Caelum | Ensino e Inova??o www.caelum.com.br 2012/5/9 Jim Gish : > On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >> Hi >> This error occurs because you have two applicable methods, namely: >> >> *) comparing(IntMapper) >> >> *) comparing(LongMapper) >> >> When there are multiple applicable methods, the compiler tries to >> disambiguate the call-site using a routine called most-specific. The >> goal is to look at the two ambiguous signatures and see if one can be >> considered 'more specific' than the other. For instance, if you have two >> applicable methods, one accepting an Object, and the other accepting an >> Integer, the latter would 'win' as Integer is a subtype of Object. >> >> What's happening in this case is that the compiler doesn't have enough >> information to disambiguate the call-site by just looking at the method >> signatures - that's because IntMapper and LongMapper are two unrelated >> types, so the compiler doesn't know which method to pick - hence the >> ambiguity error. >> >> We are currently exploring the design space, to see if we can allow some >> restricted form of structural subtyping in the most specific algorithm >> (this would allow, i.e. to prefer IntMapper to LongMapper because the >> return type of the IntMapper's descriptor is more specific). >> >> Maurizio >> >> On 06-Mar-12 8:51 PM, Antoras wrote: >>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>> Person which has a method getAge(). If the return value of this method >>> is 'int' the following inline Mapper-object produces an error: >>> >>> Comparator ? c = comparing((Person p1) -> ? p1.getAge()); >>> >>> If the return type is 'Integer' the above code works. >>> >>> This line: >>> >>> Comparator ? c = comparing(Person::getAge); >>> >>> works neither with 'Integer' nor with 'int'; >>> >>> Is this expected behavior or should the type checker recognize that >>> IntMapper is the first one to "choose"? >>> >>> >>> The error message: >>> >>> ListTest.java:203: error: reference to comparing is ambiguous, both >>> methodcomparing(LongMapper) in Comparators and method >>> comparing(IntMapper) in Comparators match >>> ? ? ? ?Comparator ? c = comparing((Person p1) -> ? p1.getAge()); >>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^ >>> ? ? ?where T#1,T#2 are type-variables: >>> ? ? ? ?T#1 extends Object declared in methodcomparing(LongMapper) >>> ? ? ? ?T#2 extends Object declared in methodcomparing(IntMapper) >>> >> > I think I have the same problem here: > > ? ?StringJoinerTest.java:46: error: reference to mapReduce is > ? ?ambiguous, both method mapReduce(LongMapper ? ?T>,long,LongBinaryOperator) in Iterable and method > ? ?mapReduce(DoubleMapper,double,DoubleBinaryOperator) in > ? ?Iterable match > ? ? ? ? ? ? int altCompOfStringsLength = lastNames.mapReduce( e -> > ? ?e.length(), 0, (a, b) -> a+b); > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^ > ? ? ? where T is a type-variable: > ? ? ? ? T extends Object declared in interface Iterable > ? ?1 error > > So, how does one go about disambiguating this, other than breaking out > the lambda expressions (and somewhat defeating the point of the > compactness value). ?This, for example, works: > > ? ? ? ? int stringsLength = lastNames.map(e -> e.length()).reduce(0, > (a, b) -> a+b); > > Thanks, > ? ?Jim > > > > From peter.levart at marand.si Thu May 10 02:57:42 2012 From: peter.levart at marand.si (Peter Levart) Date: Thu, 10 May 2012 11:57:42 +0200 Subject: SIGSEGV when debugging an overriden defender method Message-ID: <4580597.mLhouXqAZz@peterl.marand.si> I'm trying to debug code compiled and run by the latest lambda JDK (hg rev 5323 (8310b83837de)) with: -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:60486,suspend=y,server=n and get a SIGSEGV from JVM immediately after debug session starts (connection to debugger is established): # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f55398405d9, pid=18635, tid=140003423139584 # # JRE version: 8.0 # Java VM: OpenJDK 64-Bit Server VM (24.0-b07 mixed mode linux-amd64 compressed oops) # Problematic frame: # V [libjvm.so+0x5c95d9] JvmtiEnv::GetClassMethods(oopDesc*, int*, _jmethodID***)+0x249 The code normally runs without a problem (when not debugging). It also runs to completion when debugging but no breakpoints are set. I traced down the crash to occur when the breakpoint is set inside a method in a class that @Overrides a defender method from the interface. Here's an example: import java.util.*; public class SimpleTest { static class MyList extends ArrayList { @Override public Iterable sorted(Comparator comparator) { return super.sorted(comparator); // <- put breakpoint HERE! } } public static void main(String[] args) { MyList strings = new MyList<>(); strings.add("aaa"); strings.add("bbb"); strings.add("ccc"); System.out.println(strings.sorted(Comparators.reverseOrder())); } } I can send the hs_errXXX.log file if needed, but I think the above example can be used to reproduce the problem... Regards, Peter From maurizio.cimadamore at oracle.com Thu May 10 03:08:20 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 10 May 2012 11:08:20 +0100 Subject: ambiguous type inference while working with primitives In-Reply-To: <4FAAC7F4.3020501@oracle.com> References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> Message-ID: <4FAB9394.4010201@oracle.com> On 09/05/12 20:39, Jim Gish wrote: > On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >> Hi >> This error occurs because you have two applicable methods, namely: >> >> *) comparing(IntMapper) >> >> *) comparing(LongMapper) >> >> When there are multiple applicable methods, the compiler tries to >> disambiguate the call-site using a routine called most-specific. The >> goal is to look at the two ambiguous signatures and see if one can be >> considered 'more specific' than the other. For instance, if you have two >> applicable methods, one accepting an Object, and the other accepting an >> Integer, the latter would 'win' as Integer is a subtype of Object. >> >> What's happening in this case is that the compiler doesn't have enough >> information to disambiguate the call-site by just looking at the method >> signatures - that's because IntMapper and LongMapper are two unrelated >> types, so the compiler doesn't know which method to pick - hence the >> ambiguity error. >> >> We are currently exploring the design space, to see if we can allow some >> restricted form of structural subtyping in the most specific algorithm >> (this would allow, i.e. to prefer IntMapper to LongMapper because the >> return type of the IntMapper's descriptor is more specific). >> >> Maurizio >> >> On 06-Mar-12 8:51 PM, Antoras wrote: >>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>> Person which has a method getAge(). If the return value of this method >>> is 'int' the following inline Mapper-object produces an error: >>> >>> Comparator c = comparing((Person p1) -> p1.getAge()); >>> >>> If the return type is 'Integer' the above code works. >>> >>> This line: >>> >>> Comparator c = comparing(Person::getAge); >>> >>> works neither with 'Integer' nor with 'int'; >>> >>> Is this expected behavior or should the type checker recognize that >>> IntMapper is the first one to "choose"? >>> >>> >>> The error message: >>> >>> ListTest.java:203: error: reference to comparing is ambiguous, both >>> methodcomparing(LongMapper) in Comparators and method >>> comparing(IntMapper) in Comparators match >>> Comparator c = comparing((Person p1) -> p1.getAge()); >>> ^ >>> where T#1,T#2 are type-variables: >>> T#1 extends Object declared in methodcomparing(LongMapper) >>> T#2 extends Object declared in methodcomparing(IntMapper) >>> > I think I have the same problem here: > > StringJoinerTest.java:46: error: reference to mapReduce is > ambiguous, both method mapReduce(LongMapper T>,long,LongBinaryOperator) in Iterable and method > mapReduce(DoubleMapper,double,DoubleBinaryOperator) in > Iterable match > int altCompOfStringsLength = lastNames.mapReduce( e -> > e.length(), 0, (a, b) -> a+b); > ^ > where T is a type-variable: > T extends Object declared in interface Iterable > 1 error > > So, how does one go about disambiguating this, other than breaking out > the lambda expressions (and somewhat defeating the point of the > compactness value). This, for example, works: > > int stringsLength = lastNames.map(e -> e.length()).reduce(0, > (a, b) -> a+b); > > Thanks, This is a straight compiler bug when dealing with structural most specific check with functional interfaces containing wildcards. I will fix it soon. Maurizio > Jim > > > From maurizio.cimadamore at oracle.com Thu May 10 03:16:41 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 10 May 2012 11:16:41 +0100 Subject: ambiguous type inference while working with primitives In-Reply-To: References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> Message-ID: <4FAB9589.1040005@oracle.com> On 10/05/12 05:14, Paulo Silveira wrote: > I do have problems with even simpler cases (build 1.8.0-jdk8-b35-20120502): > > List list = new ArrayList<>(); > list.sort(Comparators.comparing(Object::toString)); > list.sort(Comparators.comparing((o) -> o.toString())); > > both examples fail compiling: > > error: no suitable method found for comparing(member reference) > list.sorted(Comparators.comparing(Object::toString)); > ^ > method Comparators.comparing(DoubleMapper) is not applicable > (cyclic inference - cannot infer target type for given > lambda/method reference expression) > method Comparators.comparing(LongMapper) is not applicable > (cyclic inference - cannot infer target type for given > lambda/method reference expression) > method Comparators.comparing(IntMapper) is not applicable > (cyclic inference - cannot infer target type for given > lambda/method reference expression) > method Comparators.comparing(Mapper) is not applicable > (cyclic inference - cannot infer target type for given > lambda/method reference expression) > where T#1,T#2,T#3,T#4,U are type-variables: > T#1 extends Object declared in methodcomparing(DoubleMapper) > T#2 extends Object declared in methodcomparing(LongMapper) > T#3 extends Object declared in methodcomparing(IntMapper) > T#4 extends Object declared in methodcomparing(Mapper) > U extends Comparable declared in method > comparing(Mapper) > > It does not work even if I try to split the statement: > > Comparator c = Comparators.comparing(Object::toString); > > The only way to make it work is to be explicit: > > list.sort(Comparators.comparing(Object::toString)); This is a known problem - if the method accepts only one parameter you are kinda stuck in an inference cycle - in order to infer the method signature you'd need info from the lambda parameter types, but since those types are implicit (same applies for method references), the compiler needs to look at the method signature to understand how to type-check the lambda. We are exploring some solutions in order to mitigate this problem. > > Going further, couldn't we have an List.sort overload to directly > receive a Mapper as parameter? > > public> void sort(Mapper > mapper) default { > Collections.sort(this, new MapperComparator(mapper)); > } > > This would make possible to invoke a quite short list.sort(Class::getAttribute); I'll leave this to our library gurus ;-) Maurizio > > > -- > Paulo Silveira > Caelum | Ensino e Inova??o > www.caelum.com.br > > > 2012/5/9 Jim Gish: >> On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >>> Hi >>> This error occurs because you have two applicable methods, namely: >>> >>> *) comparing(IntMapper) >>> >>> *) comparing(LongMapper) >>> >>> When there are multiple applicable methods, the compiler tries to >>> disambiguate the call-site using a routine called most-specific. The >>> goal is to look at the two ambiguous signatures and see if one can be >>> considered 'more specific' than the other. For instance, if you have two >>> applicable methods, one accepting an Object, and the other accepting an >>> Integer, the latter would 'win' as Integer is a subtype of Object. >>> >>> What's happening in this case is that the compiler doesn't have enough >>> information to disambiguate the call-site by just looking at the method >>> signatures - that's because IntMapper and LongMapper are two unrelated >>> types, so the compiler doesn't know which method to pick - hence the >>> ambiguity error. >>> >>> We are currently exploring the design space, to see if we can allow some >>> restricted form of structural subtyping in the most specific algorithm >>> (this would allow, i.e. to prefer IntMapper to LongMapper because the >>> return type of the IntMapper's descriptor is more specific). >>> >>> Maurizio >>> >>> On 06-Mar-12 8:51 PM, Antoras wrote: >>>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>>> Person which has a method getAge(). If the return value of this method >>>> is 'int' the following inline Mapper-object produces an error: >>>> >>>> Comparator c = comparing((Person p1) -> p1.getAge()); >>>> >>>> If the return type is 'Integer' the above code works. >>>> >>>> This line: >>>> >>>> Comparator c = comparing(Person::getAge); >>>> >>>> works neither with 'Integer' nor with 'int'; >>>> >>>> Is this expected behavior or should the type checker recognize that >>>> IntMapper is the first one to "choose"? >>>> >>>> >>>> The error message: >>>> >>>> ListTest.java:203: error: reference to comparing is ambiguous, both >>>> methodcomparing(LongMapper) in Comparators and method >>>> comparing(IntMapper) in Comparators match >>>> Comparator c = comparing((Person p1) -> p1.getAge()); >>>> ^ >>>> where T#1,T#2 are type-variables: >>>> T#1 extends Object declared in methodcomparing(LongMapper) >>>> T#2 extends Object declared in methodcomparing(IntMapper) >>>> >> I think I have the same problem here: >> >> StringJoinerTest.java:46: error: reference to mapReduce is >> ambiguous, both method mapReduce(LongMapper> T>,long,LongBinaryOperator) in Iterable and method >> mapReduce(DoubleMapper,double,DoubleBinaryOperator) in >> Iterable match >> int altCompOfStringsLength = lastNames.mapReduce( e -> >> e.length(), 0, (a, b) -> a+b); >> ^ >> where T is a type-variable: >> T extends Object declared in interface Iterable >> 1 error >> >> So, how does one go about disambiguating this, other than breaking out >> the lambda expressions (and somewhat defeating the point of the >> compactness value). This, for example, works: >> >> int stringsLength = lastNames.map(e -> e.length()).reduce(0, >> (a, b) -> a+b); >> >> Thanks, >> Jim >> >> >> >> From maurizio.cimadamore at oracle.com Thu May 10 04:25:22 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Thu, 10 May 2012 11:25:22 +0000 Subject: hg: lambda/lambda/langtools: Fix: structural most specific doesn't handle cases with wildcards in functional interfaces Message-ID: <20120510112526.2097A47223@hg.openjdk.java.net> Changeset: d7183160a00e Author: mcimadamore Date: 2012-05-10 12:24 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/d7183160a00e Fix: structural most specific doesn't handle cases with wildcards in functional interfaces ! src/share/classes/com/sun/tools/javac/comp/Resolve.java + test/tools/javac/lambda/MostSpecific04.java + test/tools/javac/lambda/MostSpecific05.java From brian.goetz at oracle.com Thu May 10 08:09:07 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 10 May 2012 11:09:07 -0400 Subject: ambiguous type inference while working with primitives In-Reply-To: <4FAAC7F4.3020501@oracle.com> References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> Message-ID: <4FABDA13.7000701@oracle.com> A few comments on this: 1. I think we have a solution in the works for the ambiguity problem you ran into, but it is not yet implemented. So, stay tuned. 2. The fused operations mapReduce may go away. These fused ops exist only as a workaround for the pain of reducing over unnecessarily boxed values (think: mapReduce(String::length, Integer::plus)). The library can fuse map/reduce even without a fused method, so this is entirely about boxing. When we figure out the primitives story, this methods may or may not go away. 3. To answer your question: if you want to force a particular overload resolution, cast one or more lambda to the appropriate SAM type, such as mapReduce( (DoubleMapper) ..., (DoubleBinaryOperator) ...) On 5/9/2012 3:39 PM, Jim Gish wrote: > On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >> Hi >> This error occurs because you have two applicable methods, namely: >> >> *) comparing(IntMapper) >> >> *) comparing(LongMapper) >> >> When there are multiple applicable methods, the compiler tries to >> disambiguate the call-site using a routine called most-specific. The >> goal is to look at the two ambiguous signatures and see if one can be >> considered 'more specific' than the other. For instance, if you have two >> applicable methods, one accepting an Object, and the other accepting an >> Integer, the latter would 'win' as Integer is a subtype of Object. >> >> What's happening in this case is that the compiler doesn't have enough >> information to disambiguate the call-site by just looking at the method >> signatures - that's because IntMapper and LongMapper are two unrelated >> types, so the compiler doesn't know which method to pick - hence the >> ambiguity error. >> >> We are currently exploring the design space, to see if we can allow some >> restricted form of structural subtyping in the most specific algorithm >> (this would allow, i.e. to prefer IntMapper to LongMapper because the >> return type of the IntMapper's descriptor is more specific). >> >> Maurizio >> >> On 06-Mar-12 8:51 PM, Antoras wrote: >>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>> Person which has a method getAge(). If the return value of this method >>> is 'int' the following inline Mapper-object produces an error: >>> >>> Comparator c = comparing((Person p1) -> p1.getAge()); >>> >>> If the return type is 'Integer' the above code works. >>> >>> This line: >>> >>> Comparator c = comparing(Person::getAge); >>> >>> works neither with 'Integer' nor with 'int'; >>> >>> Is this expected behavior or should the type checker recognize that >>> IntMapper is the first one to "choose"? >>> >>> >>> The error message: >>> >>> ListTest.java:203: error: reference to comparing is ambiguous, both >>> methodcomparing(LongMapper) in Comparators and method >>> comparing(IntMapper) in Comparators match >>> Comparator c = comparing((Person p1) -> p1.getAge()); >>> ^ >>> where T#1,T#2 are type-variables: >>> T#1 extends Object declared in methodcomparing(LongMapper) >>> T#2 extends Object declared in methodcomparing(IntMapper) >>> >> > I think I have the same problem here: > > StringJoinerTest.java:46: error: reference to mapReduce is > ambiguous, both method mapReduce(LongMapper T>,long,LongBinaryOperator) in Iterable and method > mapReduce(DoubleMapper,double,DoubleBinaryOperator) in > Iterable match > int altCompOfStringsLength = lastNames.mapReduce( e -> > e.length(), 0, (a, b) -> a+b); > ^ > where T is a type-variable: > T extends Object declared in interface Iterable > 1 error > > So, how does one go about disambiguating this, other than breaking out > the lambda expressions (and somewhat defeating the point of the > compactness value). This, for example, works: > > int stringsLength = lastNames.map(e -> e.length()).reduce(0, > (a, b) -> a+b); > > Thanks, > Jim > > > > From brian.goetz at oracle.com Thu May 10 08:35:30 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 10 May 2012 11:35:30 -0400 Subject: ambiguous type inference while working with primitives In-Reply-To: References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> Message-ID: <4FABE042.1090506@oracle.com> > It does not work even if I try to split the statement: > > Comparator c = Comparators.comparing(Object::toString); > > The only way to make it work is to be explicit: > > list.sort(Comparators.comparing(Object::toString)); Or to cast the Comparator argument. > Going further, couldn't we have an List.sort overload to directly > receive a Mapper as parameter? This is actually where we started, and we pulled backed to the current situation after getting some API feedback. The first question anyone asks when you add List.sort(Mapper) is "how do I sort in reverse order?" If the argument is a Comparator, there is a reverse() method on Comparator to reverse the order: List.sort(comparing(Foo::getSize).reverse()) But without the indirection of going through Comparator, you have to add sortReverse (or disappoint those who want to sort in the opposite order.) This in itself isn't bad, but there is a combinatorial explosion when you consider all the cases: argument type x direction x serial/parallel which yields the following explosion of sort() methods on List: sort(Mapper) sort(IntMapper) sort(LongMapper) sort(DoubleMapper) reverseSort(Mapper) reverseSort(IntMapper) reverseSort(LongMapper) reverseSort(DoubleMapper) parallelSort(Mapper) parallelSort(IntMapper) parallelSort(LongMapper) parallelSort(DoubleMapper) parallelReverseSort(Mapper) parallelReverseSort(IntMapper) parallelReverseSort(LongMapper) parallelReverseSort(DoubleMapper) So, in the light of morning, that looks like a false economy. By going through Comparator, which handles all the overloads of Mapper types, plus reverse (using a smaller total number of methods), this boils down to: sort(Comparator) parallelSort(Comparator) which seems more manageable. The little extra bit of explicitness to make a comparator out of a Mapper is not so bad. > public> void sort(Mapper > mapper) default { > Collections.sort(this, new MapperComparator(mapper)); > } > > This would make possible to invoke a quite short list.sort(Class::getAttribute); > > > -- > Paulo Silveira > Caelum | Ensino e Inova??o > www.caelum.com.br > > > 2012/5/9 Jim Gish: >> On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >>> Hi >>> This error occurs because you have two applicable methods, namely: >>> >>> *) comparing(IntMapper) >>> >>> *) comparing(LongMapper) >>> >>> When there are multiple applicable methods, the compiler tries to >>> disambiguate the call-site using a routine called most-specific. The >>> goal is to look at the two ambiguous signatures and see if one can be >>> considered 'more specific' than the other. For instance, if you have two >>> applicable methods, one accepting an Object, and the other accepting an >>> Integer, the latter would 'win' as Integer is a subtype of Object. >>> >>> What's happening in this case is that the compiler doesn't have enough >>> information to disambiguate the call-site by just looking at the method >>> signatures - that's because IntMapper and LongMapper are two unrelated >>> types, so the compiler doesn't know which method to pick - hence the >>> ambiguity error. >>> >>> We are currently exploring the design space, to see if we can allow some >>> restricted form of structural subtyping in the most specific algorithm >>> (this would allow, i.e. to prefer IntMapper to LongMapper because the >>> return type of the IntMapper's descriptor is more specific). >>> >>> Maurizio >>> >>> On 06-Mar-12 8:51 PM, Antoras wrote: >>>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>>> Person which has a method getAge(). If the return value of this method >>>> is 'int' the following inline Mapper-object produces an error: >>>> >>>> Comparator c = comparing((Person p1) -> p1.getAge()); >>>> >>>> If the return type is 'Integer' the above code works. >>>> >>>> This line: >>>> >>>> Comparator c = comparing(Person::getAge); >>>> >>>> works neither with 'Integer' nor with 'int'; >>>> >>>> Is this expected behavior or should the type checker recognize that >>>> IntMapper is the first one to "choose"? >>>> >>>> >>>> The error message: >>>> >>>> ListTest.java:203: error: reference to comparing is ambiguous, both >>>> methodcomparing(LongMapper) in Comparators and method >>>> comparing(IntMapper) in Comparators match >>>> Comparator c = comparing((Person p1) -> p1.getAge()); >>>> ^ >>>> where T#1,T#2 are type-variables: >>>> T#1 extends Object declared in methodcomparing(LongMapper) >>>> T#2 extends Object declared in methodcomparing(IntMapper) >>>> >>> >> I think I have the same problem here: >> >> StringJoinerTest.java:46: error: reference to mapReduce is >> ambiguous, both method mapReduce(LongMapper> T>,long,LongBinaryOperator) in Iterable and method >> mapReduce(DoubleMapper,double,DoubleBinaryOperator) in >> Iterable match >> int altCompOfStringsLength = lastNames.mapReduce( e -> >> e.length(), 0, (a, b) -> a+b); >> ^ >> where T is a type-variable: >> T extends Object declared in interface Iterable >> 1 error >> >> So, how does one go about disambiguating this, other than breaking out >> the lambda expressions (and somewhat defeating the point of the >> compactness value). This, for example, works: >> >> int stringsLength = lastNames.map(e -> e.length()).reduce(0, >> (a, b) -> a+b); >> >> Thanks, >> Jim >> >> >> >> > From brian.goetz at oracle.com Thu May 10 08:36:13 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 10 May 2012 11:36:13 -0400 Subject: SIGSEGV when debugging an overriden defender method In-Reply-To: <4580597.mLhouXqAZz@peterl.marand.si> References: <4580597.mLhouXqAZz@peterl.marand.si> Message-ID: <4FABE06D.1060305@oracle.com> Thanks for the bug report! On 5/10/2012 5:57 AM, Peter Levart wrote: > I'm trying to debug code compiled and run by the latest lambda JDK (hg rev > 5323 (8310b83837de)) with: > > -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:60486,suspend=y,server=n > > and get a SIGSEGV from JVM immediately after debug session starts (connection > to debugger is established): > > # > # A fatal error has been detected by the Java Runtime Environment: > # > # SIGSEGV (0xb) at pc=0x00007f55398405d9, pid=18635, tid=140003423139584 > # > # JRE version: 8.0 > # Java VM: OpenJDK 64-Bit Server VM (24.0-b07 mixed mode linux-amd64 > compressed oops) > # Problematic frame: > # V [libjvm.so+0x5c95d9] JvmtiEnv::GetClassMethods(oopDesc*, int*, > _jmethodID***)+0x249 > > The code normally runs without a problem (when not debugging). It also runs to > completion when debugging but no breakpoints are set. > > I traced down the crash to occur when the breakpoint is set inside a method in > a class that @Overrides a defender method from the interface. > > Here's an example: > > import java.util.*; > > public class SimpleTest > { > static class MyList extends ArrayList > { > @Override > public Iterable sorted(Comparator comparator) > { > return super.sorted(comparator); //<- put breakpoint HERE! > } > } > > public static void main(String[] args) > { > MyList strings = new MyList<>(); > strings.add("aaa"); > strings.add("bbb"); > strings.add("ccc"); > > System.out.println(strings.sorted(Comparators.reverseOrder())); > } > } > > > I can send the hs_errXXX.log file if needed, but I think the above example can > be used to reproduce the problem... > > > Regards, > > Peter > > > > From brian.goetz at oracle.com Thu May 10 11:44:43 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 10 May 2012 14:44:43 -0400 Subject: Reducers - A Library and Model for Collection Processing In-Reply-To: <4FA99B83.8040100@univ-mlv.fr> References: <4FA99B83.8040100@univ-mlv.fr> Message-ID: <4FAC0C9B.7080201@oracle.com> All roads lead to Rome... On 5/8/2012 6:17 PM, R?mi Forax wrote: > An article by Rich Hickey, > http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html > > Hum, the design remember me something :) > > R?mi > > From robert.field at oracle.com Thu May 10 13:11:48 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Thu, 10 May 2012 20:11:48 +0000 Subject: hg: lambda/lambda/jdk: Backout runtime approach to var args (will implement using bridges) Message-ID: <20120510201206.AAC9847237@hg.openjdk.java.net> Changeset: ef9074ded24b Author: Robert Field Date: 2012-05-10 11:48 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/ef9074ded24b Backout runtime approach to var args (will implement using bridges) ! src/share/classes/java/lang/invoke/InnerClassGenerator.java - src/share/classes/java/lang/invoke/InstructionAdapter.java ! src/share/classes/java/lang/invoke/LambdaMetafactory.java From maurizio.cimadamore at oracle.com Fri May 11 05:48:14 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Fri, 11 May 2012 12:48:14 +0000 Subject: hg: lambda/lambda/langtools: Fix: Misc translation fixes to inner class translator Message-ID: <20120511124819.34C194727E@hg.openjdk.java.net> Changeset: 74ccb485dc29 Author: mcimadamore Date: 2012-05-11 13:47 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/74ccb485dc29 Fix: Misc translation fixes to inner class translator *) super calls in argument position lead to verifier error *) in some cases varargs method references lead to runtime CCE ! src/share/classes/com/sun/tools/javac/comp/Check.java ! src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java ! src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java ! src/share/classes/com/sun/tools/javac/tree/JCTree.java + test/tools/javac/lambda/LambdaExpr17.java + test/tools/javac/lambda/MethodReference36.java From jim.gish at oracle.com Fri May 11 07:54:26 2012 From: jim.gish at oracle.com (Jim Gish) Date: Fri, 11 May 2012 10:54:26 -0400 Subject: ambiguous type inference while working with primitives In-Reply-To: <4FABDA13.7000701@oracle.com> References: <4F5678CE.4050804@antoras.de> <4F56A16C.3030306@oracle.com> <4FAAC7F4.3020501@oracle.com> <4FABDA13.7000701@oracle.com> Message-ID: <4FAD2822.6030408@oracle.com> On 05/10/2012 11:09 AM, Brian Goetz wrote: > A few comments on this: > > 1. I think we have a solution in the works for the ambiguity problem > you ran into, but it is not yet implemented. So, stay tuned. > > 2. The fused operations mapReduce may go away. These fused ops exist > only as a workaround for the pain of reducing over unnecessarily boxed > values (think: mapReduce(String::length, Integer::plus)). The library > can fuse map/reduce even without a fused method, so this is entirely > about boxing. When we figure out the primitives story, this methods > may or may not go away. > > 3. To answer your question: if you want to force a particular > overload resolution, cast one or more lambda to the appropriate SAM > type, such as > > mapReduce( (DoubleMapper) ..., (DoubleBinaryOperator) ...) > > On 5/9/2012 3:39 PM, Jim Gish wrote: >> On 03/06/2012 06:44 PM, maurizio cimadamore wrote: >>> Hi >>> This error occurs because you have two applicable methods, namely: >>> >>> *) comparing(IntMapper) >>> >>> *) comparing(LongMapper) >>> >>> When there are multiple applicable methods, the compiler tries to >>> disambiguate the call-site using a routine called most-specific. The >>> goal is to look at the two ambiguous signatures and see if one can be >>> considered 'more specific' than the other. For instance, if you have >>> two >>> applicable methods, one accepting an Object, and the other accepting an >>> Integer, the latter would 'win' as Integer is a subtype of Object. >>> >>> What's happening in this case is that the compiler doesn't have enough >>> information to disambiguate the call-site by just looking at the method >>> signatures - that's because IntMapper and LongMapper are two unrelated >>> types, so the compiler doesn't know which method to pick - hence the >>> ambiguity error. >>> >>> We are currently exploring the design space, to see if we can allow >>> some >>> restricted form of structural subtyping in the most specific algorithm >>> (this would allow, i.e. to prefer IntMapper to LongMapper because the >>> return type of the IntMapper's descriptor is more specific). >>> >>> Maurizio >>> >>> On 06-Mar-12 8:51 PM, Antoras wrote: >>>> I get compiler errors due to ambiguous Mapper-objects. I have a class >>>> Person which has a method getAge(). If the return value of this method >>>> is 'int' the following inline Mapper-object produces an error: >>>> >>>> Comparator c = comparing((Person p1) -> p1.getAge()); >>>> >>>> If the return type is 'Integer' the above code works. >>>> >>>> This line: >>>> >>>> Comparator c = comparing(Person::getAge); >>>> >>>> works neither with 'Integer' nor with 'int'; >>>> >>>> Is this expected behavior or should the type checker recognize that >>>> IntMapper is the first one to "choose"? >>>> >>>> >>>> The error message: >>>> >>>> ListTest.java:203: error: reference to comparing is ambiguous, both >>>> methodcomparing(LongMapper) in Comparators and method >>>> comparing(IntMapper) in Comparators match >>>> Comparator c = comparing((Person p1) -> >>>> p1.getAge()); >>>> ^ >>>> where T#1,T#2 are type-variables: >>>> T#1 extends Object declared in >>>> methodcomparing(LongMapper) >>>> T#2 extends Object declared in >>>> methodcomparing(IntMapper) >>>> >>> >> I think I have the same problem here: >> >> StringJoinerTest.java:46: error: reference to mapReduce is >> ambiguous, both method mapReduce(LongMapper> T>,long,LongBinaryOperator) in Iterable and method >> mapReduce(DoubleMapper,double,DoubleBinaryOperator) in >> Iterable match >> int altCompOfStringsLength = lastNames.mapReduce( e -> >> e.length(), 0, (a, b) -> a+b); >> ^ >> where T is a type-variable: >> T extends Object declared in interface Iterable >> 1 error >> >> So, how does one go about disambiguating this, other than breaking out >> the lambda expressions (and somewhat defeating the point of the >> compactness value). This, for example, works: >> >> int stringsLength = lastNames.map(e -> e.length()).reduce(0, >> (a, b) -> a+b); >> >> Thanks, >> Jim >> >> >> >> Maurizio's fix solved my problem. (Thanks for the quick fix Maruizio!). I thought I tried the casting and was getting a different compile error. I'll have to go back and check. From peter.levart at marand.si Fri May 11 10:00:57 2012 From: peter.levart at marand.si (Peter Levart) Date: Fri, 11 May 2012 19:00:57 +0200 Subject: alternative implementations of Iterable and MapStream Message-ID: <167113130.kSk9fYWROc@peterl.marand.si> Hello lambdanians, I toyed a little more with the idea of using "push" processing instead of traditional "pull" that is used in current implementations of stream transformation methods of Iterable and MapStream. It turned out that it can be done and that this approach has a benefit of avoiding box/unbox-ing of pairs of values into/out of BiValue while actualy having no drawbacks (I managed to elliminate all drawbacks of my 1st implementation from a week ago). If you are interested, have a look at: https://github.com/plevart/PushPipes Basic classes are: Producable - which implements Iterable (only as a facade) MapProducable - which implements MapStream (only as a facade) both classes override all defenders from Iterable and MapStream with their own "push" implementations. Currently Producable/MapProducable are abstract classes, but they could easily be transformed into interfaces with defender methods. Regards, Peter From scottcarey at apache.org Fri May 11 10:06:06 2012 From: scottcarey at apache.org (Scott Carey) Date: Fri, 11 May 2012 10:06:06 -0700 Subject: Stream proposal and null results Message-ID: In the stream API draft proposal, I noticed that null was used to signify a failed computation or filter: Method matching = Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirst(); if (matching == null) throw new InternalError("Enclosing method not found"); return matching; It would be very useful to avoid requiring clients to check the result for null. This error prone null check pattern can be avoided and pushed into the framework with something like: return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirstOrElse(() -> throw new InternalError("Enclosing method not found")); A couple other signatures for the last line are very useful as well: .getFirstOrElse(() -> someDefaultComputation())); .getFirstOrElse(someDefaultValue)); If the only API contract for a computation with no result is to return null, then the pattern T tempVar = values.someComputations().getResult(); if (null == tempVar) { // do something about no result here } return tempVar; will be extremely common boilerplate that can be avoided . I think there are a three signatures that together remove the boilerplate. Below I have changed the name from getFirstOrElse to getFirst: void getFirst(Runnable elseAction) T getFirst(Callable elseResult) T getFirst(T elseVal) T getFirst() is then simply a shortcut for T getFirst((T)null); There is likely something more elegant than multiplying the number of method signatures for every method that has an optional result. From brian.goetz at oracle.com Fri May 11 10:55:20 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 11 May 2012 13:55:20 -0400 Subject: Stream proposal and null results In-Reply-To: References: Message-ID: <4FAD5288.7090200@oracle.com> Yes, you caught us :) Currently getFirst() is the only method that cheats in this way (using null as a sentinel), and this is generally a step in the wrong direction. A much more promising direction here would be to do something like Option (Guava) or Optional (Scala) where getFirst returns an Option, rendering it impossible for the user to "forget" to do the null check. And, of course, having the return type explicitly represent maybe-null is more self-documenting than the current prototyped approach. Moving to some sort of Option-like approach here is on our to-do list, but currently we're working through some bigger issues first, such as how the streams framework attaches to collections. A secondary benefit of this approach is that it eliminates a "garbage" variable from the client code. Such "garbage" variables can often obfuscate the flow of what's going on. So, total agreement; we just haven't gotten around to this yet. On 5/11/2012 1:06 PM, Scott Carey wrote: > In the stream API draft proposal, I noticed that null was used to signify > a failed computation or filter: > > Method matching = > Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) > .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) > .filter(m -> Arrays.equals(m.getParameterTypes(), > parameterClasses)) > .filter(m -> Objects.equals(m.getReturnType(), returnType)) > .getFirst(); > if (matching == null) > throw new InternalError("Enclosing method not found"); > return matching; > > > It would be very useful to avoid requiring clients to check the result for > null. This error prone null check pattern can be avoided and pushed into > the framework with something like: > > > return > Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) > .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) > .filter(m -> Arrays.equals(m.getParameterTypes(), > parameterClasses)) > .filter(m -> Objects.equals(m.getReturnType(), returnType)) > .getFirstOrElse(() -> throw new InternalError("Enclosing method > not found")); > > > A couple other signatures for the last line are very useful as well: > > .getFirstOrElse(() -> someDefaultComputation())); > > > .getFirstOrElse(someDefaultValue)); > > > > > If the only API contract for a computation with no result is to return > null, then the pattern > > T tempVar = values.someComputations().getResult(); > if (null == tempVar) { > // do something about no result here > } > return tempVar; > > will be extremely common boilerplate that can be avoided . > > I think there are a three signatures that together remove the boilerplate. > Below I have changed the name from getFirstOrElse to getFirst: > > void getFirst(Runnable elseAction) > > T getFirst(Callable elseResult) > T getFirst(T elseVal) > > T getFirst() is then simply a shortcut for > > T getFirst((T)null); > > > > > There is likely something more elegant than multiplying the number of > method signatures for every method that has an optional result. > > > From r.spilker at topdesk.com Wed May 2 01:09:16 2012 From: r.spilker at topdesk.com (Roel Spilker) Date: Wed, 02 May 2012 10:09:16 +0200 Subject: hg: lambda/lambda/jdk: Add String.splitAsStream(). In-Reply-To: <4FA08B76.5090700@univ-mlv.fr> References: <20120502002900.A9751470CD@hg.openjdk.java.net> <4FA08B76.5090700@univ-mlv.fr> Message-ID: <4FA0EBAC.4050500@topdesk.com> Agreed. We might not be able to change String#split, but wouldn't it make make more sense for new APIs to accept a Pattern as parameter instead of a String representing a regex pattern? Roel On 2-5-2012 3:18, R?mi Forax wrote: > On 05/02/2012 02:28 AM, stuart.marks at oracle.com wrote: >> Changeset: 08b1840dd694 >> Author: smarks >> Date: 2012-05-01 17:09 -0700 >> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08b1840dd694 >> >> Add String.splitAsStream(). >> >> ! src/share/classes/java/lang/String.java >> + test-ng/tests/org/openjdk/tests/java/lang/StringTest.java >> >> > I think these methods should be added to CharSequence. > > R?mi > > From brian.goetz at oracle.com Fri May 11 16:43:18 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 11 May 2012 19:43:18 -0400 Subject: hg: lambda/lambda/jdk: Add String.splitAsStream(). In-Reply-To: <4FA0EBAC.4050500@topdesk.com> References: <20120502002900.A9751470CD@hg.openjdk.java.net> <4FA08B76.5090700@univ-mlv.fr> <4FA0EBAC.4050500@topdesk.com> Message-ID: <4FADA416.9020703@oracle.com> Indeed. Using a String representation of regex, instead of a pattern, was pretty dumb. It is confusing, error-prone, and in return, inefficient! On 5/2/2012 4:09 AM, Roel Spilker wrote: > Agreed. We might not be able to change String#split, but wouldn't it > make make more sense for new APIs to accept a Pattern as parameter > instead of a String representing a regex pattern? > > Roel > > > On 2-5-2012 3:18, R?mi Forax wrote: >> On 05/02/2012 02:28 AM, stuart.marks at oracle.com wrote: >>> Changeset: 08b1840dd694 >>> Author: smarks >>> Date: 2012-05-01 17:09 -0700 >>> URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/08b1840dd694 >>> >>> Add String.splitAsStream(). >>> >>> ! src/share/classes/java/lang/String.java >>> + test-ng/tests/org/openjdk/tests/java/lang/StringTest.java >>> >>> >> I think these methods should be added to CharSequence. >> >> R?mi >> >> > From keith.mcguigan at oracle.com Mon May 14 10:53:06 2012 From: keith.mcguigan at oracle.com (keith.mcguigan at oracle.com) Date: Mon, 14 May 2012 17:53:06 +0000 Subject: hg: lambda/lambda/hotspot: 3 new changesets Message-ID: <20120514175315.7A775472F0@hg.openjdk.java.net> Changeset: 5bce116f4574 Author: kamg Date: 2012-05-14 11:33 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/5bce116f4574 Summary: Fix read-beyond bug in inner class attribute array ! src/share/vm/classfile/genericSignatures.cpp Changeset: d78dfe1cf509 Author: kamg Date: 2012-05-14 11:33 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/d78dfe1cf509 Summary: change GA algorithm to use iteration rather than recursion ! src/share/vm/classfile/classFileParser.cpp ! src/share/vm/classfile/defaultMethods.cpp ! src/share/vm/classfile/defaultMethods.hpp ! src/share/vm/oops/instanceKlass.cpp ! src/share/vm/oops/instanceKlass.hpp ! src/share/vm/oops/instanceKlassKlass.cpp Changeset: 0acd8d16388b Author: kamg Date: 2012-05-14 11:33 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/0acd8d16388b Summary: Implement new FD semantics with regards to abstract methods ! src/share/vm/classfile/defaultMethods.cpp From brian.goetz at oracle.com Tue May 15 11:59:43 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 15 May 2012 14:59:43 -0400 Subject: alternative implementations of Iterable and MapStream In-Reply-To: <167113130.kSk9fYWROc@peterl.marand.si> References: <167113130.kSk9fYWROc@peterl.marand.si> Message-ID: <4FB2A79F.2070302@oracle.com> We toyed with this as well and had some concerns about the approach. Since you claim this approach "has no remaining drawbacks", can you outline the list of drawbacks you started with? On 5/11/2012 1:00 PM, Peter Levart wrote: > Hello lambdanians, > > I toyed a little more with the idea of using "push" processing instead of > traditional "pull" that is used in current implementations of stream > transformation methods of Iterable and MapStream. > > It turned out that it can be done and that this approach has a benefit of > avoiding box/unbox-ing of pairs of values into/out of BiValue while actualy > having no drawbacks (I managed to elliminate all drawbacks of my 1st > implementation from a week ago). > > If you are interested, have a look at: > > https://github.com/plevart/PushPipes > > Basic classes are: > > Producable - which implements Iterable (only as a facade) > MapProducable - which implements MapStream (only as a facade) > > both classes override all defenders from Iterable and MapStream with their own > "push" implementations. > > Currently Producable/MapProducable are abstract classes, but they could easily > be transformed into interfaces with defender methods. > > > Regards, > Peter > From mike.duigou at oracle.com Tue May 15 15:04:48 2012 From: mike.duigou at oracle.com (Mike Duigou) Date: Tue, 15 May 2012 15:04:48 -0700 Subject: Lambda Libraries Iteration 1 Complete Message-ID: Lambditizens; A new binary snapshot of the the prototype Lambda branch of OpenJDK 8 is available at . Builds are available for all of the OpenJDK supported platforms. We encourage you to try out the latest lambda-enabled JVM, compiler and libraries. The new release contains enhancements to the the JVM, compiler and libraries. Of particular note are improvements to the compiler and to the libraries. The compiler now has full support for defender method semantics as per latest Featherweight Defenders document (including super calls) and structural most-specific resolution. On the libraries side, this new release contains the completion of our first iteration of the bulk data API for streams (Collection-shaped) and map streams (Map-shaped). Our goals in the first iteration of the API were; - Establish the required functionality - Prototype the parallel implementation - Look for poor interactions with boxing - Decide what we could live without - Better understand attachment to collections Definitive Non-goals for the first iteration were: - Define the final Java APIs for lambda and parallel collections - Provide complete parallel implementations - Matching performance of hand-tuned fork-join parallel algorithms - Complete handling of primitives The current non-goals will be the focus of future iterations. The upcoming iteration will be focused on defining the APIs and getting the correct attachment to existing collections data structures. The current lambda bulk data APIs are intended to provide a basic set of what we believe is the required functionality. Comments and suggestions on the API or implementation are certainly welcome, but the biggest contribution the user community can make at this point is to try out the libraries and language features using your favourite problems or refactor existing code to use lambda. Please report back on how well the features worked for your code and especially cases that didn't work well, where expected functionality was missing or where the implementation was cumbersome or considerably slower than the existing solutions. Share and discuss your findings with other developers and the lambda team on lambda-dev mailing list or at conferences and meetings. From marcos_antonio_ps at hotmail.com Tue May 15 17:54:36 2012 From: marcos_antonio_ps at hotmail.com (Marcos Antonio) Date: Wed, 16 May 2012 03:54:36 +0300 Subject: Lambda Libraries Iteration 1 Complete In-Reply-To: References: Message-ID: Hello! I was using the "lambda-8-b25-windows-x64-05_feb_2012" snapshot. Now, with the new one ("lambda-8-b39-windows-x64-11_may_2012"),I'm getting all sort of error messages, even for simple things that should work, like this code that used to compile: private void registrarObservadorAlteracaoValor(){ addPropertyChangeListener("value", e -> valorAlteradoInterno(true));} Now I get the error: C:\desenvolvimento\desenvolvimento\br\desenvolvimento\iu\CampoTextoFormatado.java:307: error: no suitable method found for addPropertyChangeListener(String,lambda) [javac] addPropertyChangeListener("value", e -> valorAlteradoInterno(true)); [javac] ^ [javac] method Container.addPropertyChangeListener(String,PropertyChangeListener) is not applicable [javac] (incompatible return type void in lambda expression) [javac] method Container.addPropertyChangeListener(PropertyChangeListener) is not applicable [javac] (actual and formal argument lists differ in length) And there are lots of other errors with basic code. Am I missing something? Do I have to provide some compiler flag? Thank you. Marcos > From: mike.duigou at oracle.com > Subject: Lambda Libraries Iteration 1 Complete > Date: Tue, 15 May 2012 15:04:48 -0700 > To: lambda-dev at openjdk.java.net > > Lambditizens; > > A new binary snapshot of the the prototype Lambda branch of OpenJDK 8 is available at . Builds are available for all of the OpenJDK supported platforms. We encourage you to try out the latest lambda-enabled JVM, compiler and libraries. > > The new release contains enhancements to the the JVM, compiler and libraries. Of particular note are improvements to the compiler and to the libraries. The compiler now has full support for defender method semantics as per latest Featherweight Defenders document (including super calls) and structural most-specific resolution. > > On the libraries side, this new release contains the completion of our first iteration of the bulk data API for streams (Collection-shaped) and map streams (Map-shaped). Our goals in the first iteration of the API were; > - Establish the required functionality > - Prototype the parallel implementation > - Look for poor interactions with boxing > - Decide what we could live without > - Better understand attachment to collections > > Definitive Non-goals for the first iteration were: > - Define the final Java APIs for lambda and parallel collections > - Provide complete parallel implementations > - Matching performance of hand-tuned fork-join parallel algorithms > - Complete handling of primitives > > The current non-goals will be the focus of future iterations. The upcoming iteration will be focused on defining the APIs and getting the correct attachment to existing collections data structures. > > The current lambda bulk data APIs are intended to provide a basic set of what we believe is the required functionality. Comments and suggestions on the API or implementation are certainly welcome, but the biggest contribution the user community can make at this point is to try out the libraries and language features using your favourite problems or refactor existing code to use lambda. Please report back on how well the features worked for your code and especially cases that didn't work well, where expected functionality was missing or where the implementation was cumbersome or considerably slower than the existing solutions. Share and discuss your findings with other developers and the lambda team on lambda-dev mailing list or at conferences and meetings. > > > From benjamin.john.evans at gmail.com Tue May 15 19:04:59 2012 From: benjamin.john.evans at gmail.com (Ben Evans) Date: Tue, 15 May 2012 23:04:59 -0300 Subject: AdoptOpenJDK Hack Day - Lambdas in London 27th May Message-ID: Hi, The London Java Community is running a lambdas hack day on Sunday May 27th. The plan for the day is to start with an introduction to the Lambdas feature and then move on to spend the rest of the day coding in teams to fully investigate the latest beta that Mike announced today. Full lists of coding tasks are still being formed, but modifying some popular Open Source libraries to make use of lambdas would be one use case that we'd expect to run on the day. Full details are here: http://www.meetup.com/Londonjavacommunity/events/64939182/ Hope to see you there on May 27th - do sign up or contact me if you have any questions. Thanks, Ben From frans at meruvian.org Tue May 15 19:10:39 2012 From: frans at meruvian.org (Frans Thamura) Date: Wed, 16 May 2012 09:10:39 +0700 Subject: [jug-leaders] AdoptOpenJDK Hack Day - Lambdas in London 27th May In-Reply-To: References: Message-ID: hi ben if you use slide, let me know, so we can "do" it here also, direct in Java island ;0 F On Wed, May 16, 2012 at 9:04 AM, Ben Evans wrote: > Hi, > > The London Java Community is running a lambdas hack day on Sunday May 27th. > > The plan for the day is to start with an introduction to the Lambdas > feature and then move on to spend the rest of the day coding in teams > to fully investigate the latest beta that Mike announced today. Full > lists of coding tasks are still being formed, but modifying some > popular Open Source libraries to make use of lambdas would be one use > case that we'd expect to run on the day. > > Full details are here: > http://www.meetup.com/Londonjavacommunity/events/64939182/ > > Hope to see you there on May 27th - do sign up or contact me if you > have any questions. > > Thanks, > > Ben From sam at sampullara.com Tue May 15 19:44:41 2012 From: sam at sampullara.com (Sam Pullara) Date: Tue, 15 May 2012 19:44:41 -0700 Subject: Lambda Libraries Iteration 1 Complete In-Reply-To: References: Message-ID: It must not be completely broken, my https://github.com/spullara/java-future-jdk8 library still builds and tests with this release. Sam On Tue, May 15, 2012 at 5:54 PM, Marcos Antonio < marcos_antonio_ps at hotmail.com> wrote: > > Hello! I was using the "lambda-8-b25-windows-x64-05_feb_2012" snapshot. > Now, with the new one ("lambda-8-b39-windows-x64-11_may_2012"),I'm getting > all sort of error messages, even for simple things that should work, like > this code that used to compile: private void > registrarObservadorAlteracaoValor(){ addPropertyChangeListener("value", > e -> valorAlteradoInterno(true));} Now I get the error: > C:\desenvolvimento\desenvolvimento\br\desenvolvimento\iu\CampoTextoFormatado.java:307: > error: no suitable method found for > addPropertyChangeListener(String,lambda) [javac] > addPropertyChangeListener("value", e -> valorAlteradoInterno(true)); > [javac] ^ [javac] method > Container.addPropertyChangeListener(String,PropertyChangeListener) is not > applicable [javac] (incompatible return type void in lambda > expression) [javac] method > Container.addPropertyChangeListener(PropertyChangeListener) is not > applicable [javac] (actual and formal argument lists di! > ffer in length) And there are lots of other errors with basic code. Am I > missing something? Do I have to provide some compiler flag? Thank you. > Marcos > From: mike.duigou at oracle.com > > Subject: Lambda Libraries Iteration 1 Complete > > Date: Tue, 15 May 2012 15:04:48 -0700 > > To: lambda-dev at openjdk.java.net > > > > Lambditizens; > > > > A new binary snapshot of the the prototype Lambda branch of OpenJDK 8 is > available at . Builds are available for all > of the OpenJDK supported platforms. We encourage you to try out the latest > lambda-enabled JVM, compiler and libraries. > > > > The new release contains enhancements to the the JVM, compiler and > libraries. Of particular note are improvements to the compiler and to the > libraries. The compiler now has full support for defender method semantics > as per latest Featherweight Defenders document (including super calls) and > structural most-specific resolution. > > > > On the libraries side, this new release contains the completion of our > first iteration of the bulk data API for streams (Collection-shaped) and > map streams (Map-shaped). Our goals in the first iteration of the API were; > > - Establish the required functionality > > - Prototype the parallel implementation > > - Look for poor interactions with boxing > > - Decide what we could live without > > - Better understand attachment to collections > > > > Definitive Non-goals for the first iteration were: > > - Define the final Java APIs for lambda and parallel collections > > - Provide complete parallel implementations > > - Matching performance of hand-tuned fork-join parallel algorithms > > - Complete handling of primitives > > > > The current non-goals will be the focus of future iterations. The > upcoming iteration will be focused on defining the APIs and getting the > correct attachment to existing collections data structures. > > > > The current lambda bulk data APIs are intended to provide a basic set of > what we believe is the required functionality. Comments and suggestions on > the API or implementation are certainly welcome, but the biggest > contribution the user community can make at this point is to try out the > libraries and language features using your favourite problems or refactor > existing code to use lambda. Please report back on how well the features > worked for your code and especially cases that didn't work well, where > expected functionality was missing or where the implementation was > cumbersome or considerably slower than the existing solutions. Share and > discuss your findings with other developers and the lambda team on > lambda-dev mailing list or at conferences and meetings. > > > > > > > > > From bitterfoxc at gmail.com Tue May 15 20:29:31 2012 From: bitterfoxc at gmail.com (bitter_fox) Date: Wed, 16 May 2012 12:29:31 +0900 Subject: Lambda Libraries Iteration 1 Complete In-Reply-To: References: Message-ID: Hi Marcos, >From the change[1], the body which returns void of lambda expression was restricted as Block-Type. So, you have to write it as block today: private void registrarObservadorAlteracaoVa lor() { addPropertyChangeListener("value", e -> {valorAlteradoInterno(true);}); } Please try this code. Regard, bitter_fox [1]: http://mail.openjdk.java.net/pipermail/lambda-dev/2012-April/004745.html Sorry, I've forgot that I add lambda-dev at openjdk.java.net to Cc. So, I send this mail again. 2012/5/16 Marcos Antonio > > Hello! I was using the "lambda-8-b25-windows-x64-05_feb_2012" snapshot. > Now, with the new one ("lambda-8-b39-windows-x64-11_may_2012"),I'm getting > all sort of error messages, even for simple things that should work, like > this code that used to compile: private void > registrarObservadorAlteracaoValor(){ addPropertyChangeListener("value", > e -> valorAlteradoInterno(true));} Now I get the error: > C:\desenvolvimento\desenvolvimento\br\desenvolvimento\iu\CampoTextoFormatado.java:307: > error: no suitable method found for > addPropertyChangeListener(String,lambda) [javac] > addPropertyChangeListener("value", e -> valorAlteradoInterno(true)); > [javac] ^ [javac] method > Container.addPropertyChangeListener(String,PropertyChangeListener) is not > applicable [javac] (incompatible return type void in lambda > expression) [javac] method > Container.addPropertyChangeListener(PropertyChangeListener) is not > applicable [javac] (actual and formal argument lists di! > ffer in length) And there are lots of other errors with basic code. Am I > missing something? Do I have to provide some compiler flag? Thank you. > Marcos > From: mike.duigou at oracle.com > > Subject: Lambda Libraries Iteration 1 Complete > > Date: Tue, 15 May 2012 15:04:48 -0700 > > To: lambda-dev at openjdk.java.net > > > > Lambditizens; > > > > A new binary snapshot of the the prototype Lambda branch of OpenJDK 8 is > available at . Builds are available for all > of the OpenJDK supported platforms. We encourage you to try out the latest > lambda-enabled JVM, compiler and libraries. > > > > The new release contains enhancements to the the JVM, compiler and > libraries. Of particular note are improvements to the compiler and to the > libraries. The compiler now has full support for defender method semantics > as per latest Featherweight Defenders document (including super calls) and > structural most-specific resolution. > > > > On the libraries side, this new release contains the completion of our > first iteration of the bulk data API for streams (Collection-shaped) and > map streams (Map-shaped). Our goals in the first iteration of the API were; > > - Establish the required functionality > > - Prototype the parallel implementation > > - Look for poor interactions with boxing > > - Decide what we could live without > > - Better understand attachment to collections > > > > Definitive Non-goals for the first iteration were: > > - Define the final Java APIs for lambda and parallel collections > > - Provide complete parallel implementations > > - Matching performance of hand-tuned fork-join parallel algorithms > > - Complete handling of primitives > > > > The current non-goals will be the focus of future iterations. The > upcoming iteration will be focused on defining the APIs and getting the > correct attachment to existing collections data structures. > > > > The current lambda bulk data APIs are intended to provide a basic set of > what we believe is the required functionality. Comments and suggestions on > the API or implementation are certainly welcome, but the biggest > contribution the user community can make at this point is to try out the > libraries and language features using your favourite problems or refactor > existing code to use lambda. Please report back on how well the features > worked for your code and especially cases that didn't work well, where > expected functionality was missing or where the implementation was > cumbersome or considerably slower than the existing solutions. Share and > discuss your findings with other developers and the lambda team on > lambda-dev mailing list or at conferences and meetings. > > > > > > > > > From martijnverburg at gmail.com Wed May 16 01:02:52 2012 From: martijnverburg at gmail.com (Martijn Verburg) Date: Wed, 16 May 2012 09:02:52 +0100 Subject: [jug-leaders] Re: AdoptOpenJDK Hack Day - Lambdas in London 27th May In-Reply-To: References: Message-ID: Hi Frans, Assuming we have time we'll write this up as a template for the Adopt OpenJDK program. We're a little swamped writing up the latest events though, so we might not quite get to this one. Cheers, Martijn On 16 May 2012 03:10, Frans Thamura wrote: > hi ben > > if you use slide, let me know, so we can "do" it here also, direct in > Java island ;0 > > F > > On Wed, May 16, 2012 at 9:04 AM, Ben Evans > wrote: >> Hi, >> >> The London Java Community is running a lambdas hack day on Sunday May 27th. >> >> The plan for the day is to start with an introduction to the Lambdas >> feature and then move on to spend the rest of the day coding in teams >> to fully investigate the latest beta that Mike announced today. Full >> lists of coding tasks are still being formed, but modifying some >> popular Open Source libraries to make use of lambdas would be one use >> case that we'd expect to run on the day. >> >> Full details are here: >> http://www.meetup.com/Londonjavacommunity/events/64939182/ >> >> Hope to see you there on May 27th - do sign up or contact me if you >> have any questions. >> >> Thanks, >> >> Ben From marcos_antonio_ps at hotmail.com Wed May 16 03:21:02 2012 From: marcos_antonio_ps at hotmail.com (Marcos Antonio) Date: Wed, 16 May 2012 13:21:02 +0300 Subject: Lambda Libraries Iteration 1 Complete In-Reply-To: References: , , Message-ID: Thank you a lot, bitter_fox. That solved the problem. Marcos Date: Wed, 16 May 2012 12:25:47 +0900 Subject: Re: Lambda Libraries Iteration 1 Complete From: bitterfoxc at gmail.com To: marcos_antonio_ps at hotmail.com Hi Marcos, >From the change[1], the body which returns void of lambda expression was restricted as Block-Type. So, you have to write it as block today: private void registrarObservadorAlteracaoValor() { addPropertyChangeListener("value", e -> {valorAlteradoInterno(true);}); } Please try this code. Regard, bitter_fox [1]: http://mail.openjdk.java.net/pipermail/lambda-dev/2012-April/004745.html 2012/5/16 Marcos Antonio Hello! I was using the "lambda-8-b25-windows-x64-05_feb_2012" snapshot. Now, with the new one ("lambda-8-b39-windows-x64-11_may_2012"),I'm getting all sort of error messages, even for simple things that should work, like this code that used to compile: private void registrarObservadorAlteracaoValor(){ addPropertyChangeListener("value", e -> valorAlteradoInterno(true));} Now I get the error: C:\desenvolvimento\desenvolvimento\br\desenvolvimento\iu\CampoTextoFormatado.java:307: error: no suitable method found for addPropertyChangeListener(String,lambda) [javac] addPropertyChangeListener("value", e -> valorAlteradoInterno(true)); [javac] ^ [javac] method Container.addPropertyChangeListener(String,PropertyChangeListener) is not applicable [javac] (incompatible return type void in lambda expression) [javac] method Container.addPropertyChangeListener(PropertyChangeListener) is not applicable [javac] (actual and formal argument lists di! ffer in length) And there are lots of other errors with basic code. Am I missing something? Do I have to provide some compiler flag? Thank you. Marcos > From: mike.duigou at oracle.com > Subject: Lambda Libraries Iteration 1 Complete > Date: Tue, 15 May 2012 15:04:48 -0700 > To: lambda-dev at openjdk.java.net > > Lambditizens; > > A new binary snapshot of the the prototype Lambda branch of OpenJDK 8 is available at . Builds are available for all of the OpenJDK supported platforms. We encourage you to try out the latest lambda-enabled JVM, compiler and libraries. > > The new release contains enhancements to the the JVM, compiler and libraries. Of particular note are improvements to the compiler and to the libraries. The compiler now has full support for defender method semantics as per latest Featherweight Defenders document (including super calls) and structural most-specific resolution. > > On the libraries side, this new release contains the completion of our first iteration of the bulk data API for streams (Collection-shaped) and map streams (Map-shaped). Our goals in the first iteration of the API were; > - Establish the required functionality > - Prototype the parallel implementation > - Look for poor interactions with boxing > - Decide what we could live without > - Better understand attachment to collections > > Definitive Non-goals for the first iteration were: > - Define the final Java APIs for lambda and parallel collections > - Provide complete parallel implementations > - Matching performance of hand-tuned fork-join parallel algorithms > - Complete handling of primitives > > The current non-goals will be the focus of future iterations. The upcoming iteration will be focused on defining the APIs and getting the correct attachment to existing collections data structures. > > The current lambda bulk data APIs are intended to provide a basic set of what we believe is the required functionality. Comments and suggestions on the API or implementation are certainly welcome, but the biggest contribution the user community can make at this point is to try out the libraries and language features using your favourite problems or refactor existing code to use lambda. Please report back on how well the features worked for your code and especially cases that didn't work well, where expected functionality was missing or where the implementation was cumbersome or considerably slower than the existing solutions. Share and discuss your findings with other developers and the lambda team on lambda-dev mailing list or at conferences and meetings. > > > From peter.levart at gmail.com Wed May 16 14:46:38 2012 From: peter.levart at gmail.com (Peter Levart) Date: Wed, 16 May 2012 23:46:38 +0200 Subject: alternative implementations of Iterable and MapStream In-Reply-To: <4FB2A79F.2070302@oracle.com> References: <167113130.kSk9fYWROc@peterl.marand.si> <4FB2A79F.2070302@oracle.com> Message-ID: <6589569.pDRJXG2IE0@cube> The first naive implementation, that I scraped, was based on a doubly-linked list of pipe nodes that was built as a result of composing lazy operations (.map().filter().sorted()...). There was the main driving loop at the head of the this same list that iterated over source elements and pushed them down the pipe. The drawbacks of this approach were: 1. the state that was maintained in the buffering nodes (.sorted()) prevented multiple concurrent (not necessarily multi threaded) iterations (the pipe was "occupied" by a single iteration). 2. half-built pipe could not be used as a "prefix" for building multiple different continuations (each parent node could only have a single child) 3. the approach to obtain "first" result was to issue a "long-break" out of driving loop using a sub-type of RuntimeException. Now my current approach is on one hand very similar to the approach with Iterables. The building of a chain of "Producables" is similar to building a chain of Iterables - at each step the child Producable is created that has a reference to the parent - single parent can have multiple children - drawback #2 eliminated. The Producable is a factory for Producers (like Iterable is for Iterators). The main Producable API is: public abstract class Producable implements Iterable { public Producer producer(Transformer downstream); public Producer producer(Consumer consumer); } If you have a chain of: producable1 <- producable2 <- ... <- producableN then a call to producableN.producer(consumer) creates a reverse chain of: producer1 -> transformer2 -> ... -> transformerN -> consumer and returns head producer1. So each call to producer() starts an independent producing session (eliminated drawback #1). A Transformer is a Producer and a Consumer: public interface Producer { /** * Try to produce one piece of output. One call to this method produces at most one piece of output, * but need not produce any output. * * @return true if this producer has more output to produce or false if it has exhausted all output */ boolean produce(); } public interface Consumer { /** * Consumes one object. * * @param t the object to consume */ void consume(T t); } public interface Transformer extends Consumer, Producer { /** * @return true if this transformer is in a state that allows consuming input so that the * next call to {@link #consume} will not throw {@link IllegalStateException}. */ boolean canConsume(); /** * @param t the object to consume * @throws IllegalStateException if this transformer is in a state that doesn't allow consuming */ @Override void consume(T t) throws IllegalStateException; } This way it's easy to set-up a context where you have a head producer and a tail consumer accessible inside a particular custom producing loop so you can control how much you produce and when to stop producing (until first result or until second or until first that matches, etc.) - eliminated drawback #3 The Producer/Consumer/Transformer API allows piecewise producing in spite of Transformers that compress (.filter()), expand (.flatMap()) or buffer the entire stream (.sorted()). The only remaining drawback is that this approach is different than the known approach using Iterable API, so it is maybe harder to understand. But this could be internal API that is not exposed to the client and it has this single advantage or ability to "push" down tuples of values without boxing (a method can have multiple parameters but only a single result). Regards, Peter On Tuesday, May 15, 2012 02:59:43 PM Brian Goetz wrote: > We toyed with this as well and had some concerns about the approach. > Since you claim this approach "has no remaining drawbacks", can you > outline the list of drawbacks you started with? > > On 5/11/2012 1:00 PM, Peter Levart wrote: > > Hello lambdanians, > > > > I toyed a little more with the idea of using "push" processing instead of > > traditional "pull" that is used in current implementations of stream > > transformation methods of Iterable and MapStream. > > > > It turned out that it can be done and that this approach has a benefit of > > avoiding box/unbox-ing of pairs of values into/out of BiValue while > > actualy > > having no drawbacks (I managed to elliminate all drawbacks of my 1st > > implementation from a week ago). > > > > If you are interested, have a look at: > > > > https://github.com/plevart/PushPipes > > > > Basic classes are: > > > > Producable - which implements Iterable (only as a facade) > > MapProducable - which implements MapStream (only as a facade) > > > > both classes override all defenders from Iterable and MapStream with their > > own "push" implementations. > > > > Currently Producable/MapProducable are abstract classes, but they could > > easily be transformed into interfaces with defender methods. > > > > > > Regards, > > Peter From tomasz.kowalczewski at gmail.com Thu May 17 03:33:59 2012 From: tomasz.kowalczewski at gmail.com (Tomasz Kowalczewski) Date: Thu, 17 May 2012 12:33:59 +0200 Subject: Iterable::forEach not returning Iterable Message-ID: Hi, I was trying out the new jdk8 build with lambdas and while doing some simple towards-lamda-refactoring I stumbled on following use case: List files... files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); I wanted to inject some debugging code inside this chain using forEach and realized that it returns void and not Iterable. Its default delegates to Iterables::forEach that returns Interable, so I guess it is just a matter of deciding if forEach should seal the pipe or allow more processing. Based on my example I think there is a great value in changing the return type from void as in my opinion it will be harder to debug and step through such lambdanized code than through several (ugly) for-each loops doing same work. P.S.: Atttaching eclipse debugger to this code being run in a simple main() instantly crashes the debugged JVM. But I guess debugging is not yet supported anyway :) -- Regards, Tomasz Kowalczewski From forax at univ-mlv.fr Thu May 17 06:26:24 2012 From: forax at univ-mlv.fr (=?utf-8?B?UmVtaSBGb3JheA==?=) Date: Thu, 17 May 2012 15:26:24 +0200 Subject: =?utf-8?B?UmU6IEl0ZXJhYmxlOjpmb3JFYWNoIG5vdCByZXR1cm5pbmcgSXRlcmFibGU=?= Message-ID: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> You can use map(it -> { Log.log(it); return it; }). instead of forEach. R?mi Sent from my Phone ----- Reply message ----- From: "Tomasz Kowalczewski" To: "lambda-dev" Subject: Iterable::forEach not returning Iterable Date: Thu, May 17, 2012 12:33 Hi, I was trying out the new jdk8 build with lambdas and while doing some simple towards-lamda-refactoring I stumbled on following use case: List files... files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); I wanted to inject some debugging code inside this chain using forEach and realized that it returns void and not Iterable. Its default delegates to Iterables::forEach that returns Interable, so I guess it is just a matter of deciding if forEach should seal the pipe or allow more processing. Based on my example I think there is a great value in changing the return type from void as in my opinion it will be harder to debug and step through such lambdanized code than through several (ugly) for-each loops doing same work. P.S.: Atttaching eclipse debugger to this code being run in a simple main() instantly crashes the debugged JVM. But I guess debugging is not yet supported anyway :) -- Regards, Tomasz Kowalczewski From brian.goetz at oracle.com Thu May 17 07:04:54 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 10:04:54 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: Message-ID: <4FB50586.3010309@oracle.com> Your observation that Iterables.forEach returns the Iterable is simply vestigial evidence that we originally tried it as you suggest and fell back to the current API. The problem is one of semantics. The semantics of forEach is eager; an eager operation doesn't return until all the elements have been processed. While a "lazy forEach" is possible, it is less natural (and therefore more confusing), and, as you point out, the compelling case for a lazy forEach is debugging. Debugging is important, but not so enough as to distort the semantics of the model. We have toyed with the idea of a "tee(Block)" method for introducing the desired debuggability (one of the biggest challenges in mentally shifting to laziness is debugging -- the operations are interleaved and there is no natural place to put the breakpoint and see an intermediate computation.) But we are focusing on higher-order issues first, such as how things fit into the collection framework, how we'll deal with primitives, etc. On 5/17/2012 6:33 AM, Tomasz Kowalczewski wrote: > Hi, > > I was trying out the new jdk8 build with lambdas and while doing some > simple towards-lamda-refactoring I stumbled on following use case: > > List files... > files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); > > I wanted to inject some debugging code inside this chain using forEach > and realized that it returns void and not Iterable. Its default > delegates to Iterables::forEach that returns Interable, so I guess it > is just a matter of deciding if forEach should seal the pipe or allow > more processing. > > Based on my example I think there is a great value in changing the > return type from void as in my opinion it will be harder to debug and > step through such lambdanized code than through several (ugly) > for-each loops doing same work. > > P.S.: Atttaching eclipse debugger to this code being run in a simple > main() instantly crashes the debugged JVM. But I guess debugging is > not yet supported anyway :) > From brian.goetz at oracle.com Thu May 17 07:05:28 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 10:05:28 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> Message-ID: <4FB505A8.7040703@oracle.com> Of course, no one would write production code like this. Mappers are supposed to be side-effect-free. But it is an acceptable sin for temporary debugging code. On 5/17/2012 9:26 AM, Remi Forax wrote: > You can use > map(it -> { > Log.log(it); > return it; > }). > instead of forEach. > > R?mi > > Sent from my Phone > > ----- Reply message ----- > From: "Tomasz Kowalczewski" > To: "lambda-dev" > Subject: Iterable::forEach not returning Iterable > Date: Thu, May 17, 2012 12:33 > > > Hi, > > I was trying out the new jdk8 build with lambdas and while doing some > simple towards-lamda-refactoring I stumbled on following use case: > > List files... > files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); > > I wanted to inject some debugging code inside this chain using forEach > and realized that it returns void and not Iterable. Its default > delegates to Iterables::forEach that returns Interable, so I guess it > is just a matter of deciding if forEach should seal the pipe or allow > more processing. > > Based on my example I think there is a great value in changing the > return type from void as in my opinion it will be harder to debug and > step through such lambdanized code than through several (ugly) > for-each loops doing same work. > > P.S.: Atttaching eclipse debugger to this code being run in a simple > main() instantly crashes the debugged JVM. But I guess debugging is > not yet supported anyway :) > From brian.goetz at oracle.com Thu May 17 07:18:35 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 10:18:35 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: Message-ID: <4FB508BB.60400@oracle.com> Your observation that Iterables.forEach returns the Iterable is simply vestigial evidence that we originally tried it as you suggest and fell back to the current API. The problem is one of semantics. The semantics of forEach is eager; an eager operation doesn't return until all the elements have been processed. While a "lazy forEach" is possible, it is less natural (and therefore more confusing), and, as you point out, the compelling case for a lazy forEach is debugging. Debugging is important, but not so enough as to distort the semantics of the model. We have toyed with the idea of a "tee(Block)" method for introducing the desired debuggability (one of the biggest challenges in mentally shifting to laziness is debugging -- the operations are interleaved and there is no natural place to put the breakpoint and see an intermediate computation.) But we are focusing on higher-order issues first, such as how things fit into the collection framework, how we'll deal with primitives, etc. On 5/17/2012 6:33 AM, Tomasz Kowalczewski wrote: > Hi, > > I was trying out the new jdk8 build with lambdas and while doing some > simple towards-lamda-refactoring I stumbled on following use case: > > List files... > files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); > > I wanted to inject some debugging code inside this chain using forEach > and realized that it returns void and not Iterable. Its default > delegates to Iterables::forEach that returns Interable, so I guess it > is just a matter of deciding if forEach should seal the pipe or allow > more processing. > > Based on my example I think there is a great value in changing the > return type from void as in my opinion it will be harder to debug and > step through such lambdanized code than through several (ugly) > for-each loops doing same work. > > P.S.: Atttaching eclipse debugger to this code being run in a simple > main() instantly crashes the debugged JVM. But I guess debugging is > not yet supported anyway :) > From forax at univ-mlv.fr Thu May 17 07:31:40 2012 From: forax at univ-mlv.fr (=?UTF-8?B?UsOpbWkgRm9yYXg=?=) Date: Thu, 17 May 2012 16:31:40 +0200 Subject: Iterable::forEach not returning Iterable In-Reply-To: <4FB505A8.7040703@oracle.com> References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> Message-ID: <4FB50BCC.3040904@univ-mlv.fr> On 05/17/2012 04:05 PM, Brian Goetz wrote: > Of course, no one would write production code like this. Mappers are > supposed to be side-effect-free. But it is an acceptable sin for > temporary debugging code. Haskell guys, please don't read ... but logging is side effect free until you read the log in the program. R?mi > > On 5/17/2012 9:26 AM, Remi Forax wrote: >> You can use >> map(it -> { >> Log.log(it); >> return it; >> }). >> instead of forEach. >> >> R?mi >> >> Sent from my Phone >> >> ----- Reply message ----- >> From: "Tomasz Kowalczewski" >> To: "lambda-dev" >> Subject: Iterable::forEach not returning Iterable >> Date: Thu, May 17, 2012 12:33 >> >> >> Hi, >> >> I was trying out the new jdk8 build with lambdas and while doing some >> simple towards-lamda-refactoring I stumbled on following use case: >> >> List files... >> files.filter( File::isFile ).filter( ... ).map( >> ConfigurationFile::new ); >> >> I wanted to inject some debugging code inside this chain using forEach >> and realized that it returns void and not Iterable. Its default >> delegates to Iterables::forEach that returns Interable, so I guess it >> is just a matter of deciding if forEach should seal the pipe or allow >> more processing. >> >> Based on my example I think there is a great value in changing the >> return type from void as in my opinion it will be harder to debug and >> step through such lambdanized code than through several (ugly) >> for-each loops doing same work. >> >> P.S.: Atttaching eclipse debugger to this code being run in a simple >> main() instantly crashes the debugged JVM. But I guess debugging is >> not yet supported anyway :) >> From fsarradin at gmail.com Thu May 17 10:16:37 2012 From: fsarradin at gmail.com (=?ISO-8859-1?Q?Fran=E7ois_Sarradin?=) Date: Thu, 17 May 2012 19:16:37 +0200 Subject: Iterable::forEach not returning Iterable In-Reply-To: <4FB50BCC.3040904@univ-mlv.fr> References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> <4FB50BCC.3040904@univ-mlv.fr> Message-ID: There are monads for these... ;) francois- Le 17 mai 2012 16:30, "R?mi Forax" a ?crit : > On 05/17/2012 04:05 PM, Brian Goetz wrote: > > Of course, no one would write production code like this. Mappers are > > supposed to be side-effect-free. But it is an acceptable sin for > > temporary debugging code. > > Haskell guys, please don't read ... > > but logging is side effect free until you read the log in the program. > > R?mi > > > > > On 5/17/2012 9:26 AM, Remi Forax wrote: > >> You can use > >> map(it -> { > >> Log.log(it); > >> return it; > >> }). > >> instead of forEach. > >> > >> R?mi > >> > >> Sent from my Phone > >> > >> ----- Reply message ----- > >> From: "Tomasz Kowalczewski" > >> To: "lambda-dev" > >> Subject: Iterable::forEach not returning Iterable > >> Date: Thu, May 17, 2012 12:33 > >> > >> > >> Hi, > >> > >> I was trying out the new jdk8 build with lambdas and while doing some > >> simple towards-lamda-refactoring I stumbled on following use case: > >> > >> List files... > >> files.filter( File::isFile ).filter( ... ).map( > >> ConfigurationFile::new ); > >> > >> I wanted to inject some debugging code inside this chain using forEach > >> and realized that it returns void and not Iterable. Its default > >> delegates to Iterables::forEach that returns Interable, so I guess it > >> is just a matter of deciding if forEach should seal the pipe or allow > >> more processing. > >> > >> Based on my example I think there is a great value in changing the > >> return type from void as in my opinion it will be harder to debug and > >> step through such lambdanized code than through several (ugly) > >> for-each loops doing same work. > >> > >> P.S.: Atttaching eclipse debugger to this code being run in a simple > >> main() instantly crashes the debugged JVM. But I guess debugging is > >> not yet supported anyway :) > >> > > > From brian.goetz at oracle.com Thu May 17 12:58:32 2012 From: brian.goetz at oracle.com (brian.goetz at oracle.com) Date: Thu, 17 May 2012 19:58:32 +0000 Subject: hg: lambda/lambda/jdk: Improvements to template and combo test frameworks: Message-ID: <20120517195858.1976047395@hg.openjdk.java.net> Changeset: 2979c174803e Author: briangoetz Date: 2012-05-17 15:57 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/2979c174803e Improvements to template and combo test frameworks: - Add 'debug' mode to combo test layer - Add support for separate compilation to template test layer - Add test cases for separate compilation ! combo-tests/tests/tools/javac/combo/ComboTestBase.java ! combo-tests/tests/tools/javac/combo/Diagnostics.java ! combo-tests/tests/tools/javac/combo/JavacTemplateTestBase.java + combo-tests/tests/tools/javac/combo/SeparateCompilationTest.java ! combo-tests/tests/tools/javac/combo/TemplateTest.java From scottcarey at apache.org Thu May 17 15:10:49 2012 From: scottcarey at apache.org (Scott Carey) Date: Thu, 17 May 2012 15:10:49 -0700 Subject: Stream proposal and null results In-Reply-To: <4FAD5288.7090200@oracle.com> Message-ID: On 5/11/12 10:55 AM, "Brian Goetz" wrote: >Yes, you caught us :) > >Currently getFirst() is the only method that cheats in this way (using >null as a sentinel), and this is generally a step in the wrong >direction. A much more promising direction here would be to do >something like Option (Guava) or Optional (Scala) where getFirst returns >an Option, rendering it impossible for the user to "forget" to do the >null check. There are discussions in Scala-land about the performance problems with Option[A]. What is frustrating is that the object wrapper is not necessary for correctness as long as Some(null) is not allowed -- it is simply a mismatch between the type system and runtime representation. Some have tried to have the compiler never materialize the wrapper object. Others have suggested that union types in the future would naturally allow the compiler to do all the work and never materialize such a thing at runtime. I suggest that Java leap-frog this issue and not build an object that is a wrapper for an optional value, and somehow let the type system hoist a static method into what looks like a method call on the object syntactically but is null-safe. Imagine if the following was possible with defender methods: --------------- interface Optional { final T getOrElse(T default) { Objects.getOrElse(this, default); } --------------- class Objects { ... public static getOrElse(T object, T default) { if(null == object) { return default; } else { return object; } ---------------- And similar for the T getOrElse(Callable) and void getOrElse(Runnable) variants. Then, no materialization of an option type is needed -- if java.lang.Integer implements Optional Then it pushes the null-safe static method from Objects into syntactic sugar for Integer as a null-safe method call on an Integer object: Integer nothing = null; nothing.getOrElse(3); // <-- no NPE! it is just syntactic sugar for Objects.getOrElse(nothing, 3); In short, I think there are creative ways to push this into the type system and not require object boxing. There would be other uses for this besides Option. Many other uses. I think this works as long as the defender method is final and naming collisions have a good solution -- this must be invokestatic and never resolve to invokevirtual or invokeinterface since the object may not exist. Maybe there is something creative with invokedynamic that is possible. Other methods that I would think go on Optional: map and flatMap. >And, of course, having the return type explicitly represent >maybe-null is more self-documenting than the current prototyped >approach. Moving to some sort of Option-like approach here is on our >to-do list, but currently we're working through some bigger issues >first, such as how the streams framework attaches to collections. > >A secondary benefit of this approach is that it eliminates a "garbage" >variable from the client code. Such "garbage" variables can often >obfuscate the flow of what's going on. > >So, total agreement; we just haven't gotten around to this yet. > > > >On 5/11/2012 1:06 PM, Scott Carey wrote: >> In the stream API draft proposal, I noticed that null was used to >>signify >> a failed computation or filter: >> >> Method matching = >> >>Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >> .filter(m -> Objects.equals(m.getName(), >>enclosingInfo.getName()) >> .filter(m -> Arrays.equals(m.getParameterTypes(), >> parameterClasses)) >> .filter(m -> Objects.equals(m.getReturnType(), returnType)) >> .getFirst(); >> if (matching == null) >> throw new InternalError("Enclosing method not found"); >> return matching; >> >> >> It would be very useful to avoid requiring clients to check the result >>for >> null. This error prone null check pattern can be avoided and pushed into >> the framework with something like: >> >> >> return >> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >> .filter(m -> Objects.equals(m.getName(), >>enclosingInfo.getName()) >> .filter(m -> Arrays.equals(m.getParameterTypes(), >> parameterClasses)) >> .filter(m -> Objects.equals(m.getReturnType(), returnType)) >> .getFirstOrElse(() -> throw new InternalError("Enclosing >>method >> not found")); >> >> >> A couple other signatures for the last line are very useful as well: >> >> .getFirstOrElse(() -> someDefaultComputation())); >> >> >> .getFirstOrElse(someDefaultValue)); >> >> >> >> >> If the only API contract for a computation with no result is to return >> null, then the pattern >> >> T tempVar = values.someComputations().getResult(); >> if (null == tempVar) { >> // do something about no result here >> } >> return tempVar; >> >> will be extremely common boilerplate that can be avoided . >> >> I think there are a three signatures that together remove the >>boilerplate. >> Below I have changed the name from getFirstOrElse to getFirst: >> >> void getFirst(Runnable elseAction) >> >> T getFirst(Callable elseResult) >> T getFirst(T elseVal) >> >> T getFirst() is then simply a shortcut for >> >> T getFirst((T)null); >> >> >> >> >> There is likely something more elegant than multiplying the number of >> method signatures for every method that has an optional result. >> >> >> From brian.goetz at oracle.com Thu May 17 15:27:01 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 18:27:01 -0400 Subject: Stream proposal and null results In-Reply-To: References: Message-ID: <4FB57B35.80809@oracle.com> Your Scala-bias is showing when you say "push it into the type system", like that is a good thing :) Some perspective: some have suggested that this problem isn't even big enough for a new library class like Optional -- that using null as a sentinel is good enough. So if this problem is not big enough for even one new library abstraction, it is certainly not big enough for a new language feature! What you are asking for isn't exactly static extension methods (since you wouldn't want to inject getOrElse unconditionally into Object, but only when viewing an Object as an Optional) and isn't exactly interface injection (because you'd get fouled up by the fact that your receiver is null), but more a swizzling of the two. On 5/17/2012 6:10 PM, Scott Carey wrote: > > On 5/11/12 10:55 AM, "Brian Goetz" wrote: > >> Yes, you caught us :) >> >> Currently getFirst() is the only method that cheats in this way (using >> null as a sentinel), and this is generally a step in the wrong >> direction. A much more promising direction here would be to do >> something like Option (Guava) or Optional (Scala) where getFirst returns >> an Option, rendering it impossible for the user to "forget" to do the >> null check. > > There are discussions in Scala-land about the performance problems with > Option[A]. What is frustrating is that the object wrapper is not > necessary for correctness as long as Some(null) is not allowed -- it is > simply a mismatch between the type system and runtime representation. > Some have tried to have the compiler never materialize the wrapper object. > Others have suggested that union types in the future would naturally > allow the compiler to do all the work and never materialize such a thing > at runtime. > > I suggest that Java leap-frog this issue and not build an object that is a > wrapper for an optional value, and somehow let the type system hoist a > static method into what looks like a method call on the object > syntactically but is null-safe. > > Imagine if the following was possible with defender methods: > > --------------- > interface Optional { > > final T getOrElse(T default) { > Objects.getOrElse(this, default); > } > --------------- > > class Objects { ... > > public static getOrElse(T object, T default) { > if(null == object) { > return default; > } else { > return object; > } > ---------------- > > And similar for the > T getOrElse(Callable) > and > void getOrElse(Runnable) > variants. > > Then, no materialization of an option type is needed -- if > > java.lang.Integer > implements Optional > > Then it pushes the null-safe static method from Objects into syntactic > sugar for Integer as a null-safe method call on an Integer object: > > Integer nothing = null; > nothing.getOrElse(3); //<-- no NPE! it is just syntactic sugar for > Objects.getOrElse(nothing, 3); > > > In short, I think there are creative ways to push this into the type > system and not require object boxing. There would be other uses for this > besides Option. Many other uses. I think this works as long as the > defender method is final and naming collisions have a good solution -- > this must be invokestatic and never resolve to invokevirtual or > invokeinterface since the object may not exist. Maybe there is something > creative with invokedynamic that is possible. > > > Other methods that I would think go on Optional: > > map and flatMap. > > > >> And, of course, having the return type explicitly represent >> maybe-null is more self-documenting than the current prototyped >> approach. Moving to some sort of Option-like approach here is on our >> to-do list, but currently we're working through some bigger issues >> first, such as how the streams framework attaches to collections. >> >> A secondary benefit of this approach is that it eliminates a "garbage" >> variable from the client code. Such "garbage" variables can often >> obfuscate the flow of what's going on. >> >> So, total agreement; we just haven't gotten around to this yet. >> >> >> >> On 5/11/2012 1:06 PM, Scott Carey wrote: >>> In the stream API draft proposal, I noticed that null was used to >>> signify >>> a failed computation or filter: >>> >>> Method matching = >>> >>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >>> .filter(m -> Objects.equals(m.getName(), >>> enclosingInfo.getName()) >>> .filter(m -> Arrays.equals(m.getParameterTypes(), >>> parameterClasses)) >>> .filter(m -> Objects.equals(m.getReturnType(), returnType)) >>> .getFirst(); >>> if (matching == null) >>> throw new InternalError("Enclosing method not found"); >>> return matching; >>> >>> >>> It would be very useful to avoid requiring clients to check the result >>> for >>> null. This error prone null check pattern can be avoided and pushed into >>> the framework with something like: >>> >>> >>> return >>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >>> .filter(m -> Objects.equals(m.getName(), >>> enclosingInfo.getName()) >>> .filter(m -> Arrays.equals(m.getParameterTypes(), >>> parameterClasses)) >>> .filter(m -> Objects.equals(m.getReturnType(), returnType)) >>> .getFirstOrElse(() -> throw new InternalError("Enclosing >>> method >>> not found")); >>> >>> >>> A couple other signatures for the last line are very useful as well: >>> >>> .getFirstOrElse(() -> someDefaultComputation())); >>> >>> >>> .getFirstOrElse(someDefaultValue)); >>> >>> >>> >>> >>> If the only API contract for a computation with no result is to return >>> null, then the pattern >>> >>> T tempVar = values.someComputations().getResult(); >>> if (null == tempVar) { >>> // do something about no result here >>> } >>> return tempVar; >>> >>> will be extremely common boilerplate that can be avoided . >>> >>> I think there are a three signatures that together remove the >>> boilerplate. >>> Below I have changed the name from getFirstOrElse to getFirst: >>> >>> void getFirst(Runnable elseAction) >>> >>> T getFirst(Callable elseResult) >>> T getFirst(T elseVal) >>> >>> T getFirst() is then simply a shortcut for >>> >>> T getFirst((T)null); >>> >>> >>> >>> >>> There is likely something more elegant than multiplying the number of >>> method signatures for every method that has an optional result. >>> >>> >>> > > From scolebourne at joda.org Thu May 17 15:46:16 2012 From: scolebourne at joda.org (Stephen Colebourne) Date: Thu, 17 May 2012 23:46:16 +0100 Subject: Stream proposal and null results In-Reply-To: <4FAD5288.7090200@oracle.com> References: <4FAD5288.7090200@oracle.com> Message-ID: On 11 May 2012 18:55, Brian Goetz wrote: > Yes, you caught us :) > > Currently getFirst() is the only method that cheats in this way (using > null as a sentinel), and this is generally a step in the wrong > direction. ?A much more promising direction here would be to do > something like Option (Guava) or Optional (Scala) where getFirst returns > an Option, rendering it impossible for the user to "forget" to do the > null check. ?And, of course, having the return type explicitly represent > maybe-null is more self-documenting than the current prototyped > approach. ?Moving to some sort of Option-like approach here is on our > to-do list, but currently we're working through some bigger issues > first, such as how the streams framework attaches to collections. FWIW, I think that the Option approach to null handling would be a big mistake in Java. What you end up with in that strategy is deeply nested generics like Map, List>> I have a guidance rule that 1 level of generics is OK, 2 is manageable, but 3 means you're probably missing a real domain class. Optional just gets you to that 2nd/3rd layer of generics faster than necessary. I'd also note that those nested generics tend to be harder for developers to rationalise about. Stephen From brian.goetz at oracle.com Thu May 17 16:09:32 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 19:09:32 -0400 Subject: Stream proposal and null results In-Reply-To: References: <4FAD5288.7090200@oracle.com> Message-ID: <4FB5852C.9050502@oracle.com> > FWIW, I think that the Option approach to null handling would be a > big mistake in Java. > > What you end up with in that strategy is deeply nested generics like > Map, List>> In the context of the discussion we're having, which is whether to use Optional as the return type for Stream.getFirst, this is not an issue, because the option-ness is likely to be hidden by the chaining: String s = people.filter(p -> p.age() > 18) .map(Person::getName) .getFirst() .getOrThrow(() -> new NoSuchPersonException()); Here, the Option has relatively little use on its own; you're going to immediately call one of the various getOrElse methods, and the fact that it is an Option does not appear in the source code. Similarly, if we added an Option-bearing get-like method to Map (not saying we're going to do this), the same would be true: String s = map.getAsOption(key) .getOrElse(DEFAULT_STR); Since we're not proposing anything that returns List> or anything like that, I don't get how your argument applies here, and it almost sounds like you're making the argument of "don't add any new generic container-like types to the library, because you increase the chance that people will use unwieldy generic names", which I can't say makes very much sense to me. It might be poor taste to have a nineteen-deep nested list of lists, but does that mean we shouldn't give people a generic List class? > I have a guidance rule that 1 level of generics is OK, 2 is > manageable, but 3 means you're probably missing a real domain class. > Optional just gets you to that 2nd/3rd layer of generics faster > than necessary. I'd also note that those nested generics tend to be > harder for developers to rationalise about. That's a fine rule for your code. I just don't see how adding Optional and adding a few methods that return Optional move people any closer to violating that rule? From scolebourne at joda.org Thu May 17 16:42:05 2012 From: scolebourne at joda.org (Stephen Colebourne) Date: Fri, 18 May 2012 00:42:05 +0100 Subject: Stream proposal and null results In-Reply-To: <4FB5852C.9050502@oracle.com> References: <4FAD5288.7090200@oracle.com> <4FB5852C.9050502@oracle.com> Message-ID: On 18 May 2012 00:09, Brian Goetz wrote: >> FWIW, I think that the Option ?approach to null handling would be a >> big mistake in Java. >> >> What you end up with in that strategy is deeply nested generics like >> Map, List>> > > > In the context of the discussion we're having, Sadly, for personal reasons I don't have the time to follow the discussion as much as I'd like ;-) What you describe sounds like it might be OK for Java, but I'd be concerned that it could be seen as the thin end of the wedge. Scala's usefulness is in teaching us about the complexity that doesn't work. Any Optional in a public method signature in Java is going to require explanation and has the potential to be used by others elsewhere. Stephen (returning back under his rock...) > which is whether to use > Optional as the return type for Stream.getFirst, this is not an issue, > because the option-ness is likely to be hidden by the chaining: > > ?String s = people.filter(p -> p.age() > 18) > ? ? ? ? ? ? ? ? ? .map(Person::getName) > ? ? ? ? ? ? ? ? ? .getFirst() > ? ? ? ? ? ? ? ? ? .getOrThrow(() -> new NoSuchPersonException()); > > Here, the Option has relatively little use on its own; you're going to > immediately call one of the various getOrElse methods, and the fact that it > is an Option does not appear in the source code. > > Similarly, if we added an Option-bearing get-like method to Map (not saying > we're going to do this), the same would be true: > > ?String s = map.getAsOption(key) > ? ? ? ? ? ? ? ?.getOrElse(DEFAULT_STR); > > Since we're not proposing anything that returns List> or > anything like that, I don't get how your argument applies here, and it > almost sounds like you're making the argument of "don't add any new generic > container-like types to the library, because you increase the chance that > people will use unwieldy generic names", which I can't say makes very much > sense to me. ?It might be poor taste to have a nineteen-deep nested list of > lists, but does that mean we shouldn't give people a generic List class? > > >> I have a guidance rule that 1 level of generics is OK, 2 is >> manageable, but 3 means you're probably missing a real domain class. >> Optional ?just gets you to that 2nd/3rd layer of generics faster >> than necessary. I'd also note that those nested generics tend to be >> harder for developers to rationalise about. > > > That's a fine rule for your code. ?I just don't see how adding Optional > and adding a few methods that return Optional move people any closer to > violating that rule? > From abies at adres.pl Thu May 17 17:07:04 2012 From: abies at adres.pl (Artur Biesiadowski) Date: Fri, 18 May 2012 01:07:04 +0100 Subject: Stream proposal and null results In-Reply-To: <4FB5852C.9050502@oracle.com> References: <4FAD5288.7090200@oracle.com> <4FB5852C.9050502@oracle.com> Message-ID: <4FB592A8.8090203@adres.pl> On 18/05/2012 00:09, Brian Goetz wrote: > Similarly, if we added an Option-bearing get-like method to Map (not > saying we're going to do this), the same would be true: > > String s = map.getAsOption(key) > .getOrElse(DEFAULT_STR); > String s = map.get(key) ?: DEFAULT_STR; Is it worth to 'pollute' every API in existence just to avoid introducing elvis operator? I think that we should accept that java has null very much ingrained in the culture, adapt it as 'None' Option and just add easy syntax to work with that. Garbage collector will be very happy with that solution as well. We could then have some kind of nullability indicator in type itself, either as @Nullable String s; @NotNull String s; or (just a wild idea, I know it won't fly) String? s; String! s; to indicate Option-like results in the API. Regards, Artur Biesiadowski From scottcarey at apache.org Thu May 17 17:35:41 2012 From: scottcarey at apache.org (Scott Carey) Date: Thu, 17 May 2012 17:35:41 -0700 Subject: Stream proposal and null results In-Reply-To: <4FB57B35.80809@oracle.com> Message-ID: On 5/17/12 3:27 PM, "Brian Goetz" wrote: >Your Scala-bias is showing when you say "push it into the type system", >like that is a good thing :) Scala folk say I'm Java-biased. Lets re-phrase: "I want the compiler to help users prevent mistakes with results that may be null". Or "there should be a better Java convention than wrapping every result with a temporary variable and null check". Adding extra operators like the once proposed '.?' is not a general solution ( what about getOrElse(Callable) or transform/map ?). I rarely code with Scala, I suppose I am 'biased' because spent time on mailing lists on several JVM languages, and have experimented with some prototypes in several. Java is still my day-job. Currently, the Lambda project is very interesting to me because it could solve several design issues in Apache Avro representing an API that implements functions to be composed together dynamically for dynamically flexible serialization. I'm not suggesting Java get all scala-complicated. Having the compiler help prevent user errors with null is not that far away from having the compiler know that something is an Integer and not a Long. Its not a suggestion for something like higher-kinded types or union types. > >Some perspective: some have suggested that this problem isn't even big >enough for a new library class like Optional -- that using null as a >sentinel is good enough. So if this problem is not big enough for even >one new library abstraction, it is certainly not big enough for a new >language feature! I agree that a library class like Optional or Option is not desirable. My view is that an Option/Optional object is a hack with bad performance characteristics that causes almost as many problems as it solves (does that still sound Scala biased?). You can use Google Guava or write your own if you want it -- that uses Java's current type system features to provide users with some null safety, at the expense of memory, performance. Rather than do that, I am suggesting that such an object (in the language library or in Google Guava) is not necessary if the language had better ways to deal with using an object that may be null. Having written much code and libraries that have used null sentinels in Java and dealing with the downstream consequences later, I hope for some progress here. I am not suggesting that returning a null sentinel is a bad idea. I am suggesting that there is a need for a better way to operate on a potentially null result than write a conditional statement and keep a temporary variable or resort to boxing it in something like Option. It seems natural that Lambda relates to this since it allows one to easily build compositions of functions, and some of those functions will return possibly-null results. > >What you are asking for isn't exactly static extension methods (since >you wouldn't want to inject getOrElse unconditionally into Object, but >only when viewing an Object as an Optional) I suppose injecting it into Object is possible (if namespace collision is somehow dealt with). My proposal is not the only way to deal with this. >and isn't exactly interface >injection (because you'd get fouled up by the fact that your receiver is >null), but more a swizzling of the two. I don't know enough about the guts of the JVM or the lingo to label it appropriately. I also have no idea how challenging it is to do. Perhaps there are major issues that make it a non-starter. Perhaps it is a minor change from the current defender methods. I simply hope that the idea is considered as an alternative to introducing something like Option, that is potentially more general purpose and flexible. It would be very useful (and have good performance characteristics) if API designers had the ability to make a static method with the right type signature appear to syntactically be used on the return from a method call. Perhaps this idea helps someone else come up with a better idea. Maybe having the static methods on Objects is decent for now: return Objects.orElse(Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredM ethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirst(), () -> throw new InternalError("Enclosing method not found")); That is hard to follow because you can't chain static method calls. The below is easier to follow: return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirst() .orElse(() -> throw new InternalError("Enclosing method not found")); // a static method, somehow made chainable from the result of getFirst() or even: return enclosingInfo.getEnclosingClass().getDeclaredMethods() .asList() // may not be necessary if filter or a toStream() is added to Object[] ? .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) .filter(m -> Objects.equals(m.getReturnType(), returnType)) .getFirst() .orElse(() -> throw new InternalError("Enclosing method not found")); > > > >On 5/17/2012 6:10 PM, Scott Carey wrote: >> >> On 5/11/12 10:55 AM, "Brian Goetz" wrote: >> >>> Yes, you caught us :) >>> >>> Currently getFirst() is the only method that cheats in this way (using >>> null as a sentinel), and this is generally a step in the wrong >>> direction. A much more promising direction here would be to do >>> something like Option (Guava) or Optional (Scala) where getFirst >>>returns >>> an Option, rendering it impossible for the user to "forget" to do the >>> null check. >> >> There are discussions in Scala-land about the performance problems with >> Option[A]. What is frustrating is that the object wrapper is not >> necessary for correctness as long as Some(null) is not allowed -- it is >> simply a mismatch between the type system and runtime representation. >> Some have tried to have the compiler never materialize the wrapper >>object. >> Others have suggested that union types in the future would naturally >> allow the compiler to do all the work and never materialize such a thing >> at runtime. >> >> I suggest that Java leap-frog this issue and not build an object that >>is a >> wrapper for an optional value, and somehow let the type system hoist a >> static method into what looks like a method call on the object >> syntactically but is null-safe. >> >> Imagine if the following was possible with defender methods: >> >> --------------- >> interface Optional { >> >> final T getOrElse(T default) { >> Objects.getOrElse(this, default); >> } >> --------------- >> >> class Objects { ... >> >> public static getOrElse(T object, T default) { >> if(null == object) { >> return default; >> } else { >> return object; >> } >> ---------------- >> >> And similar for the >> T getOrElse(Callable) >> and >> void getOrElse(Runnable) >> variants. >> >> Then, no materialization of an option type is needed -- if >> >> java.lang.Integer >> implements Optional >> >> Then it pushes the null-safe static method from Objects into syntactic >> sugar for Integer as a null-safe method call on an Integer object: >> >> Integer nothing = null; >> nothing.getOrElse(3); //<-- no NPE! it is just syntactic sugar for >> Objects.getOrElse(nothing, 3); >> >> >> In short, I think there are creative ways to push this into the type >> system and not require object boxing. There would be other uses for >>this >> besides Option. Many other uses. I think this works as long as the >> defender method is final and naming collisions have a good solution -- >> this must be invokestatic and never resolve to invokevirtual or >> invokeinterface since the object may not exist. Maybe there is >>something >> creative with invokedynamic that is possible. >> >> >> Other methods that I would think go on Optional: >> >> map and flatMap. >> >> >> >>> And, of course, having the return type explicitly represent >>> maybe-null is more self-documenting than the current prototyped >>> approach. Moving to some sort of Option-like approach here is on our >>> to-do list, but currently we're working through some bigger issues >>> first, such as how the streams framework attaches to collections. >>> >>> A secondary benefit of this approach is that it eliminates a "garbage" >>> variable from the client code. Such "garbage" variables can often >>> obfuscate the flow of what's going on. >>> >>> So, total agreement; we just haven't gotten around to this yet. >>> >>> >>> >>> On 5/11/2012 1:06 PM, Scott Carey wrote: >>>> In the stream API draft proposal, I noticed that null was used to >>>> signify >>>> a failed computation or filter: >>>> >>>> Method matching = >>>> >>>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >>>> .filter(m -> Objects.equals(m.getName(), >>>> enclosingInfo.getName()) >>>> .filter(m -> Arrays.equals(m.getParameterTypes(), >>>> parameterClasses)) >>>> .filter(m -> Objects.equals(m.getReturnType(), >>>>returnType)) >>>> .getFirst(); >>>> if (matching == null) >>>> throw new InternalError("Enclosing method not found"); >>>> return matching; >>>> >>>> >>>> It would be very useful to avoid requiring clients to check the result >>>> for >>>> null. This error prone null check pattern can be avoided and pushed >>>>into >>>> the framework with something like: >>>> >>>> >>>> return >>>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) >>>> .filter(m -> Objects.equals(m.getName(), >>>> enclosingInfo.getName()) >>>> .filter(m -> Arrays.equals(m.getParameterTypes(), >>>> parameterClasses)) >>>> .filter(m -> Objects.equals(m.getReturnType(), >>>>returnType)) >>>> .getFirstOrElse(() -> throw new InternalError("Enclosing >>>> method >>>> not found")); >>>> >>>> >>>> A couple other signatures for the last line are very useful as well: >>>> >>>> .getFirstOrElse(() -> someDefaultComputation())); >>>> >>>> >>>> .getFirstOrElse(someDefaultValue)); >>>> >>>> >>>> >>>> >>>> If the only API contract for a computation with no result is to return >>>> null, then the pattern >>>> >>>> T tempVar = values.someComputations().getResult(); >>>> if (null == tempVar) { >>>> // do something about no result here >>>> } >>>> return tempVar; >>>> >>>> will be extremely common boilerplate that can be avoided . >>>> >>>> I think there are a three signatures that together remove the >>>> boilerplate. >>>> Below I have changed the name from getFirstOrElse to getFirst: >>>> >>>> void getFirst(Runnable elseAction) >>>> >>>> T getFirst(Callable elseResult) >>>> T getFirst(T elseVal) >>>> >>>> T getFirst() is then simply a shortcut for >>>> >>>> T getFirst((T)null); >>>> >>>> >>>> >>>> >>>> There is likely something more elegant than multiplying the number of >>>> method signatures for every method that has an optional result. >>>> >>>> >>>> >> >> From brian.goetz at oracle.com Thu May 17 18:05:24 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 21:05:24 -0400 Subject: Stream proposal and null results In-Reply-To: References: Message-ID: <4FB5A054.2040407@oracle.com> >> Your Scala-bias is showing when you say "push it into the type system", >> like that is a good thing :) > > Scala folk say I'm Java-biased. My point was, messing with the type system should be a last resort, not the first one. Whatever you're measuring -- compatibility risk, engineering cost, time to market, complexity -- adding stuff to the language in general, and the type system particularly, is likely to be far more expensive than the library-centric alternatives. Sometimes library approaches aren't enough; that's why we're doing Lambda. But if there's a library alternative, that should be preferred. And Lambda is already making plenty of language changes -- some say too many -- but in any case, the bar for more must be really high. So it's really a question of "do nothing" (and live with null sentinels) vs "do something in the libraries." Having getFirst return an Option is one of the choices for doing something in the libraries. (And you've suggested some others here. Let's keep that discussion going.) I'm not trying to be difficult -- I'm just trying to channel the discussion towards something that is actually likely to have an impact. Cheers, -Brian From howard.lovatt at gmail.com Thu May 17 18:08:32 2012 From: howard.lovatt at gmail.com (Howard Lovatt) Date: Fri, 18 May 2012 11:08:32 +1000 Subject: Stream proposal and null results In-Reply-To: References: <4FB57B35.80809@oracle.com> Message-ID: I think it would be an interesting idea to inject getOrElse(T) and getOrElse(()->T) into Object. They would have wide usage beyond the lambdafied collection library. With regard to the collection library; I have found a parallel collection that does not accept null to be useful, since your maps etc. don't need to null check and the collection can use null internally to mean skip over item. If the collection didn't hold null, then returning null as a sentinel is less problematic. -- Howard. On 18 May 2012 10:35, Scott Carey wrote: > > > On 5/17/12 3:27 PM, "Brian Goetz" wrote: > > >Your Scala-bias is showing when you say "push it into the type system", > >like that is a good thing :) > > Scala folk say I'm Java-biased. > > Lets re-phrase: "I want the compiler to help users prevent mistakes with > results that may be null". Or "there should be a better Java convention > than wrapping every result with a temporary variable and null check". > Adding extra operators like the once proposed '.?' is not a general > solution ( what about getOrElse(Callable) or transform/map ?). > > I rarely code with Scala, I suppose I am 'biased' because spent time on > mailing lists on several JVM languages, and have experimented with some > prototypes in several. Java is still my day-job. Currently, the Lambda > project is very interesting to me because it could solve several design > issues in Apache Avro representing an API that implements functions to be > composed together dynamically for dynamically flexible serialization. > > > I'm not suggesting Java get all scala-complicated. Having the compiler > help prevent user errors with null is not that far away from having the > compiler know that something is an Integer and not a Long. Its not a > suggestion for something like higher-kinded types or union types. > > > > >Some perspective: some have suggested that this problem isn't even big > >enough for a new library class like Optional -- that using null as a > >sentinel is good enough. So if this problem is not big enough for even > >one new library abstraction, it is certainly not big enough for a new > >language feature! > > I agree that a library class like Optional or Option is not desirable. My > view is that an Option/Optional object is a hack with bad performance > characteristics that causes almost as many problems as it solves (does > that still sound Scala biased?). You can use Google Guava or write your > own if you want it -- that uses Java's current type system features to > provide users with some null safety, at the expense of memory, > performance. > Rather than do that, I am suggesting that such an object (in the language > library or in Google Guava) is not necessary if the language had better > ways to deal with using an object that may be null. > > Having written much code and libraries that have used null sentinels in > Java and dealing with the downstream consequences later, I hope for some > progress here. > > I am not suggesting that returning a null sentinel is a bad idea. I am > suggesting that there is a need for a better way to operate on a > potentially null result than write a conditional statement and keep a > temporary variable or resort to boxing it in something like Option. It > seems natural that Lambda relates to this since it allows one to easily > build compositions of functions, and some of those functions will return > possibly-null results. > > > > > > >What you are asking for isn't exactly static extension methods (since > >you wouldn't want to inject getOrElse unconditionally into Object, but > >only when viewing an Object as an Optional) > > I suppose injecting it into Object is possible (if namespace collision is > somehow dealt with). My proposal is not the only way to deal with this. > > >and isn't exactly interface > >injection (because you'd get fouled up by the fact that your receiver is > >null), but more a swizzling of the two. > > I don't know enough about the guts of the JVM or the lingo to label it > appropriately. I also have no idea how challenging it is to do. Perhaps > there are major issues that make it a non-starter. Perhaps it is a minor > change from the current defender methods. I simply hope that the idea is > considered as an alternative to introducing something like Option, that is > potentially more general purpose and flexible. > > It would be very useful (and have good performance characteristics) if API > designers had the ability to make a static method with the right type > signature appear to syntactically be used on the return from a method > call. Perhaps this idea helps someone else come up with a better idea. > > > Maybe having the static methods on Objects is decent for now: > > return > Objects.orElse(Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredM > ethods()) > .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) > .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) > .filter(m -> Objects.equals(m.getReturnType(), returnType)) > .getFirst(), > () -> throw new InternalError("Enclosing method not found")); > > > That is hard to follow because you can't chain static method calls. > The below is easier to follow: > > return > Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) > .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) > .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) > .filter(m -> Objects.equals(m.getReturnType(), returnType)) > .getFirst() > .orElse(() -> throw new InternalError("Enclosing method not found")); // > a static method, somehow made chainable from the result of getFirst() > > or even: > > > return enclosingInfo.getEnclosingClass().getDeclaredMethods() > .asList() // may not be necessary if filter or a toStream() is added to > Object[] ? > .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName()) > .filter(m -> Arrays.equals(m.getParameterTypes(),parameterClasses)) > .filter(m -> Objects.equals(m.getReturnType(), returnType)) > .getFirst() > .orElse(() -> throw new InternalError("Enclosing method not found")); > > > > > > > > > > > > >On 5/17/2012 6:10 PM, Scott Carey wrote: > >> > >> On 5/11/12 10:55 AM, "Brian Goetz" wrote: > >> > >>> Yes, you caught us :) > >>> > >>> Currently getFirst() is the only method that cheats in this way (using > >>> null as a sentinel), and this is generally a step in the wrong > >>> direction. A much more promising direction here would be to do > >>> something like Option (Guava) or Optional (Scala) where getFirst > >>>returns > >>> an Option, rendering it impossible for the user to "forget" to do the > >>> null check. > >> > >> There are discussions in Scala-land about the performance problems with > >> Option[A]. What is frustrating is that the object wrapper is not > >> necessary for correctness as long as Some(null) is not allowed -- it is > >> simply a mismatch between the type system and runtime representation. > >> Some have tried to have the compiler never materialize the wrapper > >>object. > >> Others have suggested that union types in the future would naturally > >> allow the compiler to do all the work and never materialize such a thing > >> at runtime. > >> > >> I suggest that Java leap-frog this issue and not build an object that > >>is a > >> wrapper for an optional value, and somehow let the type system hoist a > >> static method into what looks like a method call on the object > >> syntactically but is null-safe. > >> > >> Imagine if the following was possible with defender methods: > >> > >> --------------- > >> interface Optional { > >> > >> final T getOrElse(T default) { > >> Objects.getOrElse(this, default); > >> } > >> --------------- > >> > >> class Objects { ... > >> > >> public static getOrElse(T object, T default) { > >> if(null == object) { > >> return default; > >> } else { > >> return object; > >> } > >> ---------------- > >> > >> And similar for the > >> T getOrElse(Callable) > >> and > >> void getOrElse(Runnable) > >> variants. > >> > >> Then, no materialization of an option type is needed -- if > >> > >> java.lang.Integer > >> implements Optional > >> > >> Then it pushes the null-safe static method from Objects into syntactic > >> sugar for Integer as a null-safe method call on an Integer object: > >> > >> Integer nothing = null; > >> nothing.getOrElse(3); //<-- no NPE! it is just syntactic sugar for > >> Objects.getOrElse(nothing, 3); > >> > >> > >> In short, I think there are creative ways to push this into the type > >> system and not require object boxing. There would be other uses for > >>this > >> besides Option. Many other uses. I think this works as long as the > >> defender method is final and naming collisions have a good solution -- > >> this must be invokestatic and never resolve to invokevirtual or > >> invokeinterface since the object may not exist. Maybe there is > >>something > >> creative with invokedynamic that is possible. > >> > >> > >> Other methods that I would think go on Optional: > >> > >> map and flatMap. > >> > >> > >> > >>> And, of course, having the return type explicitly represent > >>> maybe-null is more self-documenting than the current prototyped > >>> approach. Moving to some sort of Option-like approach here is on our > >>> to-do list, but currently we're working through some bigger issues > >>> first, such as how the streams framework attaches to collections. > >>> > >>> A secondary benefit of this approach is that it eliminates a "garbage" > >>> variable from the client code. Such "garbage" variables can often > >>> obfuscate the flow of what's going on. > >>> > >>> So, total agreement; we just haven't gotten around to this yet. > >>> > >>> > >>> > >>> On 5/11/2012 1:06 PM, Scott Carey wrote: > >>>> In the stream API draft proposal, I noticed that null was used to > >>>> signify > >>>> a failed computation or filter: > >>>> > >>>> Method matching = > >>>> > >>>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) > >>>> .filter(m -> Objects.equals(m.getName(), > >>>> enclosingInfo.getName()) > >>>> .filter(m -> Arrays.equals(m.getParameterTypes(), > >>>> parameterClasses)) > >>>> .filter(m -> Objects.equals(m.getReturnType(), > >>>>returnType)) > >>>> .getFirst(); > >>>> if (matching == null) > >>>> throw new InternalError("Enclosing method not found"); > >>>> return matching; > >>>> > >>>> > >>>> It would be very useful to avoid requiring clients to check the result > >>>> for > >>>> null. This error prone null check pattern can be avoided and pushed > >>>>into > >>>> the framework with something like: > >>>> > >>>> > >>>> return > >>>> Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods()) > >>>> .filter(m -> Objects.equals(m.getName(), > >>>> enclosingInfo.getName()) > >>>> .filter(m -> Arrays.equals(m.getParameterTypes(), > >>>> parameterClasses)) > >>>> .filter(m -> Objects.equals(m.getReturnType(), > >>>>returnType)) > >>>> .getFirstOrElse(() -> throw new InternalError("Enclosing > >>>> method > >>>> not found")); > >>>> > >>>> > >>>> A couple other signatures for the last line are very useful as well: > >>>> > >>>> .getFirstOrElse(() -> someDefaultComputation())); > >>>> > >>>> > >>>> .getFirstOrElse(someDefaultValue)); > >>>> > >>>> > >>>> > >>>> > >>>> If the only API contract for a computation with no result is to return > >>>> null, then the pattern > >>>> > >>>> T tempVar = values.someComputations().getResult(); > >>>> if (null == tempVar) { > >>>> // do something about no result here > >>>> } > >>>> return tempVar; > >>>> > >>>> will be extremely common boilerplate that can be avoided . > >>>> > >>>> I think there are a three signatures that together remove the > >>>> boilerplate. > >>>> Below I have changed the name from getFirstOrElse to getFirst: > >>>> > >>>> void getFirst(Runnable elseAction) > >>>> > >>>> T getFirst(Callable elseResult) > >>>> T getFirst(T elseVal) > >>>> > >>>> T getFirst() is then simply a shortcut for > >>>> > >>>> T getFirst((T)null); > >>>> > >>>> > >>>> > >>>> > >>>> There is likely something more elegant than multiplying the number of > >>>> method signatures for every method that has an optional result. > >>>> > >>>> > >>>> > >> > >> > > > > -- -- Howard. From brian.goetz at oracle.com Thu May 17 18:14:04 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 May 2012 21:14:04 -0400 Subject: Stream proposal and null results In-Reply-To: References: <4FB57B35.80809@oracle.com> Message-ID: <4FB5A25C.5000207@oracle.com> > I think it would be an interesting idea to inject getOrElse(T) and > getOrElse(()->T) into Object. They would have wide > usage beyond the lambdafied collection library. I agree it is interesting. Sadly, this is a different kind of extension method than we're already doing, since this would have to be a static extension method (rewritten by the compiler as a static method call with the "receiver" prepended to the argument list) since otherwise calling getOrElse on a null instance would throw NPE (calling x.anything on a null x throws NPE.) C# does static extension methods; we're doing virtual extension methods. So this feature is, despite the similarity in name, farther from what we're already doing than it might appear. > With regard to the collection library; I have found a parallel > collection that does not accept null to be useful, since your maps etc. > don't need to null check and the collection can use null internally to > mean skip over item. If the collection didn't hold null, then returning > null as a sentinel is less problematic. Yes. Collections that support nulls are problematic for so many reasons. (Some collections support them; some don't.) We haven't worked out the details, but I like the idea of streams not supporting nulls. (Among other consequences, this makes the null sentinel approach not even an option for getFirst.) From peter.levart at marand.si Fri May 18 01:28:55 2012 From: peter.levart at marand.si (Peter Levart) Date: Fri, 18 May 2012 10:28:55 +0200 Subject: Stream proposal and null results In-Reply-To: <4FB5852C.9050502@oracle.com> References: <4FB5852C.9050502@oracle.com> Message-ID: <3053318.JquIsDNrGK@peterl.marand.si> On Thursday, May 17, 2012 07:09:32 PM Brian Goetz wrote: > > In the context of the discussion we're having, which is whether to use > Optional as the return type for Stream.getFirst, this is not an > issue, because the option-ness is likely to be hidden by the chaining: > > String s = people.filter(p -> p.age() > 18) > .map(Person::getName) > .getFirst() > .getOrThrow(() -> new NoSuchPersonException()); Even if you don't commit to have Option in the standard library, 3rd party libraries could interface with streams using .into(Fillable). For example: public class Option implements Fillable { private boolean hasResult; private T result; @Override public void addAll(Iterable source) { for (T t : source) { if (hasResult) throw new IllegalStateException("Not a single result"); result = t; hasResult = true; } } public T getOrElse(T defaultValue) { return hasResult ? result : defaultValue; } public T getOrElse(Factory defaultFactory) { return hasResult ? result : defaultFactory.make(); } public T getOrThrow(Factory exceptionFactory) throws E { if (hasResult) return result; throw exceptionFactory.make(); } } // so the chain above could be written as: String s = people.filter(p -> p.age() > 18) .map(Person::getName) .into(new Option()) // hm, new Option<>() does not work here currently :-( .getOrThrow(() -> new NoSuchPersonException()); Regards, Peter > > Here, the Option has relatively little use on its own; you're going to > immediately call one of the various getOrElse methods, and the fact that > it is an Option does not appear in the source code. > > Similarly, if we added an Option-bearing get-like method to Map (not > saying we're going to do this), the same would be true: > > String s = map.getAsOption(key) > .getOrElse(DEFAULT_STR); > > Since we're not proposing anything that returns List> or > anything like that, I don't get how your argument applies here, and it > almost sounds like you're making the argument of "don't add any new > generic container-like types to the library, because you increase the > chance that people will use unwieldy generic names", which I can't say > makes very much sense to me. It might be poor taste to have a > nineteen-deep nested list of lists, but does that mean we shouldn't give > people a generic List class? > > > I have a guidance rule that 1 level of generics is OK, 2 is > > manageable, but 3 means you're probably missing a real domain class. > > Optional just gets you to that 2nd/3rd layer of generics faster > > than necessary. I'd also note that those nested generics tend to be > > harder for developers to rationalise about. > > That's a fine rule for your code. I just don't see how adding > Optional and adding a few methods that return Optional move people > any closer to violating that rule? From brian.goetz at oracle.com Fri May 18 07:13:33 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 18 May 2012 10:13:33 -0400 Subject: Stream proposal and null results In-Reply-To: <3053318.JquIsDNrGK@peterl.marand.si> References: <4FB5852C.9050502@oracle.com> <3053318.JquIsDNrGK@peterl.marand.si> Message-ID: <4FB6590D.5050605@oracle.com> Good that this option is open to third-party developers even if we don't handle it now. (The design of Fillable is still in flux, so stay tuned.) The higher-level goal is to recognize that: - Some streams are known to the programmer to return exactly one element (Guava has an Iterators.getOnlyElement which enforces this) - Some streams are known to the programmer to return no more than one element and give developers tools for capturing this in their code, so they can detect invariant failures easily. On 5/18/2012 4:28 AM, Peter Levart wrote: > > On Thursday, May 17, 2012 07:09:32 PM Brian Goetz wrote: >> >> In the context of the discussion we're having, which is whether to use >> Optional as the return type for Stream.getFirst, this is not an >> issue, because the option-ness is likely to be hidden by the chaining: >> >> String s = people.filter(p -> p.age()> 18) >> .map(Person::getName) >> .getFirst() >> .getOrThrow(() -> new NoSuchPersonException()); > > Even if you don't commit to have Option in the standard library, 3rd party libraries could interface with streams using .into(Fillable). For example: > > public class Option implements Fillable > { > private boolean hasResult; > private T result; > > @Override > public void addAll(Iterable source) > { > for (T t : source) > { > if (hasResult) throw new IllegalStateException("Not a single result"); > result = t; > hasResult = true; > } > } > > public T getOrElse(T defaultValue) > { > return hasResult ? result : defaultValue; > } > > public T getOrElse(Factory defaultFactory) > { > return hasResult ? result : defaultFactory.make(); > } > > public T getOrThrow(Factory exceptionFactory) throws E > { > if (hasResult) return result; > throw exceptionFactory.make(); > } > } > > // so the chain above could be written as: > > String s = people.filter(p -> p.age()> 18) > .map(Person::getName) > .into(new Option()) // hm, new Option<>() does not work here currently :-( > .getOrThrow(() -> new NoSuchPersonException()); > > > Regards, Peter > >> >> Here, the Option has relatively little use on its own; you're going to >> immediately call one of the various getOrElse methods, and the fact that >> it is an Option does not appear in the source code. >> >> Similarly, if we added an Option-bearing get-like method to Map (not >> saying we're going to do this), the same would be true: >> >> String s = map.getAsOption(key) >> .getOrElse(DEFAULT_STR); >> >> Since we're not proposing anything that returns List> or >> anything like that, I don't get how your argument applies here, and it >> almost sounds like you're making the argument of "don't add any new >> generic container-like types to the library, because you increase the >> chance that people will use unwieldy generic names", which I can't say >> makes very much sense to me. It might be poor taste to have a >> nineteen-deep nested list of lists, but does that mean we shouldn't give >> people a generic List class? >> >>> I have a guidance rule that 1 level of generics is OK, 2 is >>> manageable, but 3 means you're probably missing a real domain class. >>> Optional just gets you to that 2nd/3rd layer of generics faster >>> than necessary. I'd also note that those nested generics tend to be >>> harder for developers to rationalise about. >> >> That's a fine rule for your code. I just don't see how adding >> Optional and adding a few methods that return Optional move people >> any closer to violating that rule? From brian.goetz at oracle.com Fri May 18 10:25:36 2012 From: brian.goetz at oracle.com (brian.goetz at oracle.com) Date: Fri, 18 May 2012 17:25:36 +0000 Subject: hg: lambda/lambda/jdk: 2 new changesets Message-ID: <20120518172616.A888C473E3@hg.openjdk.java.net> Changeset: 7e8f57b88c4f Author: briangoetz Date: 2012-05-17 22:28 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/7e8f57b88c4f Improvements in combo test framework - Add overridable getCompileOptions method to ComboTestBase - Extend debug mode to dump out all combo vars, files, and metadata - Add dump/diff program for combo log ! combo-tests/build.xml ! combo-tests/tests/tools/javac/combo/ComboTestBase.java + combo-tests/tests/tools/javac/combo/ComboTestDebug.java ! combo-tests/tests/tools/javac/combo/SeparateCompilationTest.java ! combo-tests/tests/tools/javac/combo/SourceFile.java ! combo-tests/tests/tools/javac/lambda/LambdaArgAdaptationTest.java ! combo-tests/tests/tools/javac/lambda/LambdaCaptureTest.java ! combo-tests/tests/tools/javac/lambda/LambdaReturnAdaptationTest.java ! combo-tests/tests/tools/javac/lambda/MethodRefCaptureTest.java Changeset: af5d9c636c7e Author: briangoetz Date: 2012-05-18 13:25 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/af5d9c636c7e Improvements to combo test framework to support separate compilation tests. - Introduction of "group" abstraction for source files - Order groups on the classpath in order of sorted group names - Introduce group-specific mechanism for determining compiler options - More comprehensive debug-logging mechanism ! combo-tests/tests/tools/javac/combo/ComboTestBase.java ! combo-tests/tests/tools/javac/combo/ComboTestDebug.java ! combo-tests/tests/tools/javac/combo/ComboTestMetadata.java ! combo-tests/tests/tools/javac/combo/JavacTemplateTestBase.java + combo-tests/tests/tools/javac/combo/SeparateCompilationComboTest.java ! combo-tests/tests/tools/javac/lambda/LambdaArgAdaptationTest.java ! combo-tests/tests/tools/javac/lambda/LambdaConversionTest.java ! combo-tests/tests/tools/javac/lambda/LambdaReturnAdaptationTest.java ! combo-tests/tests/tools/javac/lambda/MethodRefCaptureTest.java From brian.goetz at oracle.com Fri May 18 11:28:21 2012 From: brian.goetz at oracle.com (brian.goetz at oracle.com) Date: Fri, 18 May 2012 18:28:21 +0000 Subject: hg: lambda/lambda/jdk: Tweak build.xml for combo test to reduce report generation time Message-ID: <20120518182830.DD27D473E7@hg.openjdk.java.net> Changeset: 8545d256150b Author: briangoetz Date: 2012-05-18 14:28 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/8545d256150b Tweak build.xml for combo test to reduce report generation time ! combo-tests/build.xml From sveneric at panitz.name Sat May 19 04:02:57 2012 From: sveneric at panitz.name (Sven Eric Panitz) Date: Sat, 19 May 2012 13:02:57 +0200 Subject: experimental Implementation of Haskell List Functions with Java 8 Message-ID: <4FB77DE1.9040308@panitz.name> Hello all, this is my first post to this list and I am new to the list. So please excuse, if I bring up topics, which have allready been discussed ages ago. After a first look at the current status of project Lambda JSR 335, I found it a nice exercise to implement the complete Haskell Prelude list functions with java 8. The result of my efforts can be found on my web site at: http://panitz.name/paper/haskellPrelude With my class haskell.data.Iterables, now objects of type Iterable can make use of all Haskell list functions. Mayby this quick implementation is interesting for those guys, that develope the library for Java 8. I am not sure, but I might have found a bug in the current lambda compiler. At least I get a ClassCastException during runtime, which I cannot explain. It comes up in my implementation of the function ?permutations? (which is the most complicated of all the Haskell functions I implemented). The following implementation in terms of a private auxiliary method interleave_ compiles und runs without problem: static public Iterable> permutations(Iterable xs0){ Function2,Iterable,Iterable>> perms = (tso,is) -> { if (tso.isEmpty()) return new Nil>(); A t = head(tso); Iterable ts = tail(tso); return foldr((xs,r)->interleave_(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); }; return cons(xs0,perms.eval(xs0,new Nil())); } static private Tuple2,Iterable>> interleave_ (A t,Iterable ts,Function1 ,Iterable>f ,Iterable xs,Iterable> r){ if (xs.isEmpty()) return new Tuple2,Iterable>>(ts,r); A y = head(xs); Iterable ys = tail(xs); Tuple2,Iterable>> uszs=interleave_(t,ts,(x)->f.eval(cons(y,x)),ys,r); return new Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); } (Tuple2 is a generic class for pairs, Function(1-5) are interfaces for functions of arity 1 to 5. These are found as well on my web site.) The following alternative Implementation with a local function for the auxiliary function interleave_, compiles but gets a ClassCastException during runtime: static public Iterable> permutations2(Iterable xs0){ Function2,Iterable,Iterable>> perms = (tso,is) -> { if (tso.isEmpty()) return new Nil>(); Function5,Function1 ,Iterable>,Iterable,Iterable>,Tuple2,Iterable>>> interleave_ = (t,ts,f,xs,r) -> { if (xs.isEmpty()) return new Tuple2,Iterable>>(ts,r); A y = head(xs); Iterable ys = tail(xs); Tuple2,Iterable>> uszs=interleave_.eval(t,ts,(x)->f.eval(cons(y,x)),ys,r); return new Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); }; A t = head(tso); Iterable ts = tail(tso); return foldr((xs,r)->interleave_.eval(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); }; return cons(xs0,perms.eval(xs0,new Nil())); } Regards, Sven Eric From luc.duponcheel at gmail.com Sat May 19 05:39:57 2012 From: luc.duponcheel at gmail.com (Luc Duponcheel) Date: Sat, 19 May 2012 14:39:57 +0200 Subject: experimental Implementation of Haskell List Functions with Java 8 In-Reply-To: <4FB77DE1.9040308@panitz.name> References: <4FB77DE1.9040308@panitz.name> Message-ID: Nice! On May 19, 2012 1:04 PM, "Sven Eric Panitz" wrote: > Hello all, > this is my first post to this list and I am new to the list. So please > excuse, if I bring up topics, > which have allready been discussed ages ago. > > After a first look at the current status of project Lambda > JSR 335, I found it a nice > exercise to implement the complete Haskell Prelude list functions with > java 8. > > The result of my efforts can be found on my web site at: > http://panitz.name/paper/haskellPrelude > > With my class haskell.data.Iterables, now objects of type Iterable > can make use of all Haskell list functions. > Mayby this quick implementation is interesting for those guys, that > develope the library for Java 8. > > > > I am not sure, but I might have found a bug in the current lambda > compiler. At least I get a > ClassCastException during runtime, which I cannot explain. > > It comes up in my implementation of the function ?permutations? (which > is the most complicated > of all the Haskell functions I implemented). > > The following implementation in terms of a private auxiliary method > interleave_ compiles und runs > without problem: > > static public Iterable> permutations(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > A t = head(tso); > Iterable ts = tail(tso); > > return > > foldr((xs,r)->interleave_(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > static private Tuple2,Iterable>> interleave_ > (A t,Iterable ts,Function1 ,Iterable>f > ,Iterable xs,Iterable> r){ > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > } > > (Tuple2 is a generic class for pairs, Function(1-5) are interfaces for > functions of arity 1 to 5. > These are found as well on my web site.) > > The following alternative Implementation with a local function for the > auxiliary function interleave_, > compiles but gets a ClassCastException during runtime: > > static public Iterable> permutations2(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > > Function5,Function1 > > ,Iterable>,Iterable,Iterable>,Tuple2,Iterable>>> > interleave_ = > (t,ts,f,xs,r) -> { > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_.eval(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > }; > > A t = head(tso); > Iterable ts = tail(tso); > > return > > foldr((xs,r)->interleave_.eval(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > > Regards, > Sven Eric > > From brian.goetz at oracle.com Sat May 19 10:11:27 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 19 May 2012 13:11:27 -0400 Subject: experimental Implementation of Haskell List Functions with Java 8 In-Reply-To: <4FB77DE1.9040308@panitz.name> References: <4FB77DE1.9040308@panitz.name> Message-ID: <4FB7D43F.9060709@oracle.com> Do you know what the types involved are? What are we trying to cast to what, and where? On 5/19/2012 7:02 AM, Sven Eric Panitz wrote: > Hello all, > this is my first post to this list and I am new to the list. So please > excuse, if I bring up topics, > which have allready been discussed ages ago. > > After a first look at the current status of project Lambda > JSR 335, I found it a nice > exercise to implement the complete Haskell Prelude list functions with > java 8. > > The result of my efforts can be found on my web site at: > http://panitz.name/paper/haskellPrelude > > With my class haskell.data.Iterables, now objects of type Iterable > can make use of all Haskell list functions. > Mayby this quick implementation is interesting for those guys, that > develope the library for Java 8. > > > > I am not sure, but I might have found a bug in the current lambda > compiler. At least I get a > ClassCastException during runtime, which I cannot explain. > > It comes up in my implementation of the function ?permutations? (which > is the most complicated > of all the Haskell functions I implemented). > > The following implementation in terms of a private auxiliary method > interleave_ compiles und runs > without problem: > > static public Iterable> permutations(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > A t = head(tso); > Iterable ts = tail(tso); > > return > foldr((xs,r)->interleave_(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > static private Tuple2,Iterable>> interleave_ > (A t,Iterable ts,Function1 ,Iterable>f > ,Iterable xs,Iterable> r){ > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > } > > (Tuple2 is a generic class for pairs, Function(1-5) are interfaces for > functions of arity 1 to 5. > These are found as well on my web site.) > > The following alternative Implementation with a local function for the > auxiliary function interleave_, > compiles but gets a ClassCastException during runtime: > > static public Iterable> permutations2(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > > Function5,Function1 > ,Iterable>,Iterable,Iterable>,Tuple2,Iterable>>> > interleave_ = > (t,ts,f,xs,r) -> { > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_.eval(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > }; > > A t = head(tso); > Iterable ts = tail(tso); > > return > foldr((xs,r)->interleave_.eval(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > > Regards, > Sven Eric > From tomasz.kowalczewski at gmail.com Sun May 20 05:21:39 2012 From: tomasz.kowalczewski at gmail.com (Tomasz Kowalczewski) Date: Sun, 20 May 2012 14:21:39 +0200 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> <4FB50BCC.3040904@univ-mlv.fr> Message-ID: I understand that forEach is eager and do not suggest it should be changed (although I can imagine lazy versions on some specialized collections working just fine for the user). This is rather an argument towards something that potentially is more user friendly and is based on the fluent interface pattern. Iterable::into is eager and does return a collection which allows user to chain the calls further, why not forEach then? Also, if some collection can be a start to a lazy->lazy->eager chain of calls then I do not see why operation such as forEach cannot be a start of another such chain (l->l->e->l etc..). Tomasz On Thu, May 17, 2012 at 7:16 PM, Fran?ois Sarradin wrote: > There are monads for these... ;) > > francois- > Le 17 mai 2012 16:30, "R?mi Forax" a ?crit : > >> On 05/17/2012 04:05 PM, Brian Goetz wrote: >> > Of course, no one would write production code like this. ?Mappers are >> > supposed to be side-effect-free. ?But it is an acceptable sin for >> > temporary debugging code. >> >> Haskell guys, please don't read ... >> >> but logging is side effect free until you read the log in the program. >> >> R?mi >> >> > >> > On 5/17/2012 9:26 AM, Remi Forax wrote: >> >> You can use >> >> ? ?map(it -> ?{ >> >> ? ? ? Log.log(it); >> >> ? ? ? return it; >> >> ? ? }). >> >> instead of forEach. >> >> >> >> R?mi >> >> >> >> Sent from my Phone >> >> >> >> ----- Reply message ----- >> >> From: "Tomasz Kowalczewski" >> >> To: "lambda-dev" >> >> Subject: Iterable::forEach not returning Iterable >> >> Date: Thu, May 17, 2012 12:33 >> >> >> >> >> >> Hi, >> >> >> >> I was trying out the new jdk8 build with lambdas and while doing some >> >> simple towards-lamda-refactoring I stumbled on following use case: >> >> >> >> List ?files... >> >> files.filter( File::isFile ).filter( ... ).map( >> >> ConfigurationFile::new ); >> >> >> >> I wanted to inject some debugging code inside this chain using forEach >> >> and realized that it returns void and not Iterable. Its default >> >> delegates to Iterables::forEach that returns Interable, so I guess it >> >> is just a matter of deciding if forEach should seal the pipe or allow >> >> more processing. >> >> >> >> Based on my example I think there is a great value in changing the >> >> return type from void as in my opinion it will be harder to debug and >> >> step through such lambdanized code than through several (ugly) >> >> for-each loops doing same work. >> >> >> >> P.S.: Atttaching eclipse debugger to this code being run in a simple >> >> main() instantly crashes the debugged JVM. But I guess debugging is >> >> not yet supported anyway :) >> >> >> >> >> > From forax at univ-mlv.fr Sun May 20 05:57:46 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Sun, 20 May 2012 14:57:46 +0200 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> <4FB50BCC.3040904@univ-mlv.fr> Message-ID: <4FB8EA4A.7030002@univ-mlv.fr> On 05/20/2012 02:21 PM, Tomasz Kowalczewski wrote: > I understand that forEach is eager and do not suggest it should be > changed (although I can imagine lazy versions on some specialized > collections working just fine for the user). This is rather an > argument towards something that potentially is more user friendly and > is based on the fluent interface pattern. Iterable::into is eager and > does return a collection which allows user to chain the calls further, > why not forEach then? because there is no type in Java corresponding to the values of side effects so the return value is void (as usual). > > Also, if some collection can be a start to a lazy->lazy->eager chain > of calls then I do not see why operation such as forEach cannot be a > start of another such chain (l->l->e->l etc..). The idea is that if you have some lazy->lazy, it can perhaps be combined to create only one lazy adapter, by example, filter(f1).filter(f2) is equivalent to filter(f1 & f2), eager operations because they force evaluation haven't that property. So if you want to return an Iterable in forEach, you have to store all items in a temporary colection or you may have weird behavior. > > Tomasz R?mi From brian.goetz at oracle.com Sun May 20 07:04:25 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 20 May 2012 10:04:25 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> <4FB50BCC.3040904@univ-mlv.fr> Message-ID: <4FB8F9E9.7070209@oracle.com> The API invariant of "returns Iterable <==> is lazy" is a pretty powerful self-documentation mechanism that helps people learn about and reason confidently about what is going on. (More precisely, "returns the same stream type as the input", since returning a Collection is in some sense returning an Iterable.) Breaking this just because "someone might want to write code like this" seemed a questionable tradeoff. On 5/20/2012 8:21 AM, Tomasz Kowalczewski wrote: > I understand that forEach is eager and do not suggest it should be > changed (although I can imagine lazy versions on some specialized > collections working just fine for the user). This is rather an > argument towards something that potentially is more user friendly and > is based on the fluent interface pattern. Iterable::into is eager and > does return a collection which allows user to chain the calls further, > why not forEach then? > > Also, if some collection can be a start to a lazy->lazy->eager chain > of calls then I do not see why operation such as forEach cannot be a > start of another such chain (l->l->e->l etc..). > > Tomasz > > On Thu, May 17, 2012 at 7:16 PM, Fran?ois Sarradin wrote: >> There are monads for these... ;) >> >> francois- >> Le 17 mai 2012 16:30, "R?mi Forax" a ?crit : >> >>> On 05/17/2012 04:05 PM, Brian Goetz wrote: >>>> Of course, no one would write production code like this. Mappers are >>>> supposed to be side-effect-free. But it is an acceptable sin for >>>> temporary debugging code. >>> >>> Haskell guys, please don't read ... >>> >>> but logging is side effect free until you read the log in the program. >>> >>> R?mi >>> >>>> >>>> On 5/17/2012 9:26 AM, Remi Forax wrote: >>>>> You can use >>>>> map(it -> { >>>>> Log.log(it); >>>>> return it; >>>>> }). >>>>> instead of forEach. >>>>> >>>>> R?mi >>>>> >>>>> Sent from my Phone >>>>> >>>>> ----- Reply message ----- >>>>> From: "Tomasz Kowalczewski" >>>>> To: "lambda-dev" >>>>> Subject: Iterable::forEach not returning Iterable >>>>> Date: Thu, May 17, 2012 12:33 >>>>> >>>>> >>>>> Hi, >>>>> >>>>> I was trying out the new jdk8 build with lambdas and while doing some >>>>> simple towards-lamda-refactoring I stumbled on following use case: >>>>> >>>>> List files... >>>>> files.filter( File::isFile ).filter( ... ).map( >>>>> ConfigurationFile::new ); >>>>> >>>>> I wanted to inject some debugging code inside this chain using forEach >>>>> and realized that it returns void and not Iterable. Its default >>>>> delegates to Iterables::forEach that returns Interable, so I guess it >>>>> is just a matter of deciding if forEach should seal the pipe or allow >>>>> more processing. >>>>> >>>>> Based on my example I think there is a great value in changing the >>>>> return type from void as in my opinion it will be harder to debug and >>>>> step through such lambdanized code than through several (ugly) >>>>> for-each loops doing same work. >>>>> >>>>> P.S.: Atttaching eclipse debugger to this code being run in a simple >>>>> main() instantly crashes the debugged JVM. But I guess debugging is >>>>> not yet supported anyway :) >>>>> >>> >>> >>> >> > From fsarradin at gmail.com Sun May 20 23:25:31 2012 From: fsarradin at gmail.com (=?ISO-8859-1?Q?Fran=E7ois_Sarradin?=) Date: Mon, 21 May 2012 08:25:31 +0200 Subject: Question about Iterable.reduce signature Message-ID: Hi all, I'm looking for an answer to a question about the method reduce. But, I still haven't found it in archives of the mailing list. So here is my question: The current signature of Iterable.reduce is: T reduce(T base, BinaryOperator reducer) I would like to know why the signature doesn't look like this one? U reduce (U base, BiOp reducer) where BiOp is supposed to represent a function of two arguments of respective types T and U, that returns a value of type U. I really think that this other signature can lead to more readable code. Below is an example with, say, a set of products that you want to buy in whatever store you want. And you want to know the total. With the current version of reduce: double total = products.map(p -> p.getPrice()).reduce(0.0, (price, subTotal) -> price + subTotal); With the other version of reduce in this mail: double total = products.reduce(0.0, (p, subTotal) -> p.getPrice() + subTotal); I know that there is a method named mapReduce. But I'm still uncomfortable with it: double total = products.mapReduce(p -> p.getPrice(), 0.0, (price, subTotal) -> price + subTotal); Regards, Francois From maurizio.cimadamore at oracle.com Mon May 21 04:58:08 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Mon, 21 May 2012 11:58:08 +0000 Subject: hg: lambda/lambda/langtools: Fix: A spurious synthetic cast is added by the inner class translator when translating nested lambdas Message-ID: <20120521115814.B34A147432@hg.openjdk.java.net> Changeset: 57f54c01815e Author: mcimadamore Date: 2012-05-21 12:57 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/57f54c01815e Fix: A spurious synthetic cast is added by the inner class translator when translating nested lambdas ! src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java + test/tools/javac/lambda/LambdaExpr18.java From maurizio.cimadamore at oracle.com Mon May 21 04:59:37 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 May 2012 12:59:37 +0100 Subject: experimental Implementation of Haskell List Functions with Java 8 In-Reply-To: <4FB77DE1.9040308@panitz.name> References: <4FB77DE1.9040308@panitz.name> Message-ID: <4FBA2E29.3070400@oracle.com> Thank you for the report - it turned out javac was inserting a spurious cast as it got confused by the two layers of nested lambdas. This is now fixed in the lambda repository. Maurizio On 19/05/12 12:02, Sven Eric Panitz wrote: > Hello all, > this is my first post to this list and I am new to the list. So please > excuse, if I bring up topics, > which have allready been discussed ages ago. > > After a first look at the current status of project Lambda > JSR 335, I found it a nice > exercise to implement the complete Haskell Prelude list functions with > java 8. > > The result of my efforts can be found on my web site at: > http://panitz.name/paper/haskellPrelude > > With my class haskell.data.Iterables, now objects of type Iterable > can make use of all Haskell list functions. > Mayby this quick implementation is interesting for those guys, that > develope the library for Java 8. > > > > I am not sure, but I might have found a bug in the current lambda > compiler. At least I get a > ClassCastException during runtime, which I cannot explain. > > It comes up in my implementation of the function ?permutations? (which > is the most complicated > of all the Haskell functions I implemented). > > The following implementation in terms of a private auxiliary method > interleave_ compiles und runs > without problem: > > static public Iterable> permutations(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > A t = head(tso); > Iterable ts = tail(tso); > > return > foldr((xs,r)->interleave_(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > static private Tuple2,Iterable>> interleave_ > (A t,Iterable ts,Function1 ,Iterable>f > ,Iterable xs,Iterable> r){ > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > } > > (Tuple2 is a generic class for pairs, Function(1-5) are interfaces for > functions of arity 1 to 5. > These are found as well on my web site.) > > The following alternative Implementation with a local function for the > auxiliary function interleave_, > compiles but gets a ClassCastException during runtime: > > static public Iterable> permutations2(Iterable xs0){ > Function2,Iterable,Iterable>> perms = > (tso,is) -> { > if (tso.isEmpty()) return new Nil>(); > > Function5,Function1 > ,Iterable>,Iterable,Iterable>,Tuple2,Iterable>>> > interleave_ = > (t,ts,f,xs,r) -> { > if (xs.isEmpty()) return new > Tuple2,Iterable>>(ts,r); > A y = head(xs); > Iterable ys = tail(xs); > Tuple2,Iterable>> > uszs=interleave_.eval(t,ts,(x)->f.eval(cons(y,x)),ys,r); > return new > Tuple2,Iterable>>(cons(y,uszs.e1),cons(f.eval(cons(t,cons(y,uszs.e1))),uszs.e2)); > }; > > A t = head(tso); > Iterable ts = tail(tso); > > return > foldr((xs,r)->interleave_.eval(t,ts,(u)->u,xs,r).e2,perms.eval(ts,cons(t,is)),permutations(is)); > }; > > return cons(xs0,perms.eval(xs0,new Nil())); > } > > Regards, > Sven Eric > From brian.goetz at oracle.com Mon May 21 05:15:26 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 21 May 2012 08:15:26 -0400 Subject: Question about Iterable.reduce signature In-Reply-To: References: Message-ID: <4FBA31DE.9070107@oracle.com> What you are suggesting is to fuse mapping and reducing into a single operation. While this often makes sense, the approach you suggest gets more difficult when you want to execute in parallel. If you define your reducer over T as a (T,T) -> T (assuming associativity), then to compute the reduction in parallel, you can decompose your collection into chunks, reduce each chunk to a T, and then reduce the reduced values up the tree until you have a single T. If you define your reducer as a (T,U) -> U, you can reduce each chunk to a U, and then you have no way to combine the per-chunk Us into a single answer. On 5/21/2012 2:25 AM, Fran?ois Sarradin wrote: > Hi all, > > I'm looking for an answer to a question about the method reduce. But, I > still haven't found it in archives of the mailing list. So here is my > question: > > The current signature of Iterable.reduce is: > > T reduce(T base, BinaryOperator reducer) > > I would like to know why the signature doesn't look like this one? > > U reduce (U base, BiOp reducer) > > where BiOp is supposed to represent a function of two arguments of > respective types T and U, that returns a value of type U. > > I really think that this other signature can lead to more readable > code. Below is an example with, say, a set of products that you want to buy > in whatever store you want. And you want to know the total. > > With the current version of reduce: > > double total = products.map(p -> p.getPrice()).reduce(0.0, (price, > subTotal) -> price + subTotal); > > With the other version of reduce in this mail: > > double total = products.reduce(0.0, (p, subTotal) -> p.getPrice() + > subTotal); > > I know that there is a method named mapReduce. But I'm still uncomfortable > with it: > > double total = products.mapReduce(p -> p.getPrice(), 0.0, (price, > subTotal) -> price + subTotal); > > > Regards, > > Francois > From yshavit at akiban.com Mon May 21 07:15:16 2012 From: yshavit at akiban.com (Yuval Shavit) Date: Mon, 21 May 2012 10:15:16 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: <4FB8EA4A.7030002@univ-mlv.fr> References: <201205171326.q4HDQMRU006593@monge.univ-mlv.fr> <4FB505A8.7040703@oracle.com> <4FB50BCC.3040904@univ-mlv.fr> <4FB8EA4A.7030002@univ-mlv.fr> Message-ID: On Sun, May 20, 2012 at 8:57 AM, R?mi Forax wrote: > On 05/20/2012 02:21 PM, Tomasz Kowalczewski wrote: > > I understand that forEach is eager and do not suggest it should be > > changed (although I can imagine lazy versions on some specialized > > collections working just fine for the user). This is rather an > > argument towards something that potentially is more user friendly and > > is based on the fluent interface pattern. Iterable::into is eager and > > does return a collection which allows user to chain the calls further, > > why not forEach then? > > because there is no type in Java corresponding to the values > of side effects so the return value is void (as usual). Many methods have "this" as the type+value of side effects: StringBuilder.append's overloads are a perfect example. More generally, any time I see a method that returns back "this" or any of the method's other arguments, I take that as a pretty clear sign that the returned object has been modified. Personally, I'd like to see *more* of that in libraries; for instance, there are definitely times I've wished that Collections.sort returned back the array I had just passed in. From neal at gafter.com Mon May 21 08:42:59 2012 From: neal at gafter.com (Neal Gafter) Date: Mon, 21 May 2012 08:42:59 -0700 Subject: Question about Iterable.reduce signature In-Reply-To: <4FBA31DE.9070107@oracle.com> References: <4FBA31DE.9070107@oracle.com> Message-ID: I agree. Fran?ois is requesting a *fold *operation, which compared to map-reduce is more expressive (every map-reduce can be expressed as a fold, but not vice-versa) and has more precisely defined semantics (map-reduce depends on associativity). The left fold is a natural operation to provide on lazy sequences, since it processes values in a well-defined order and consumes one value at a time from the left. The right fold, which is what he requested, requires eager evaluation of the sequence, since it starts its computation at the tail end. It therefore has all of the performances disadvantages of eager evaluation without the parallelizability. (Nevertheless, right fold is occasionally the best fit for the semantics of the problem to be solved) One streaming analog to the left-fold operation is called *scan* or *prefix sum*[1], and there is a natural parallel analog called *parallel prefix*[2]. A surprising number of problems can be reduced naturally to an application of this primitive. It is natural to consider this for the set of operations common between the lazy and parallel collection APIs. Cheers, Neal [1] http://en.wikipedia.org/wiki/Prefix_sum [2] http://ocw.mit.edu/courses/mathematics/18-337j-applied-parallel-computing-sma-5505-spring-2005/lecture-notes/chapter_3.pdf On Mon, May 21, 2012 at 5:15 AM, Brian Goetz wrote: > What you are suggesting is to fuse mapping and reducing into a single > operation. While this often makes sense, the approach you suggest gets > more difficult when you want to execute in parallel. > > If you define your reducer over T as a (T,T) -> T (assuming > associativity), then to compute the reduction in parallel, you can > decompose your collection into chunks, reduce each chunk to a T, and > then reduce the reduced values up the tree until you have a single T. > > If you define your reducer as a (T,U) -> U, you can reduce each chunk to > a U, and then you have no way to combine the per-chunk Us into a single > answer. > > On 5/21/2012 2:25 AM, Fran?ois Sarradin wrote: > > Hi all, > > > > I'm looking for an answer to a question about the method reduce. But, I > > still haven't found it in archives of the mailing list. So here is my > > question: > > > > The current signature of Iterable.reduce is: > > > > T reduce(T base, BinaryOperator reducer) > > > > I would like to know why the signature doesn't look like this one? > > > > U reduce (U base, BiOp reducer) > > > > where BiOp is supposed to represent a function of two arguments of > > respective types T and U, that returns a value of type U. > > > > I really think that this other signature can lead to more readable > > code. Below is an example with, say, a set of products that you want to > buy > > in whatever store you want. And you want to know the total. > > > > With the current version of reduce: > > > > double total = products.map(p -> p.getPrice()).reduce(0.0, (price, > > subTotal) -> price + subTotal); > > > > With the other version of reduce in this mail: > > > > double total = products.reduce(0.0, (p, subTotal) -> p.getPrice() + > > subTotal); > > > > I know that there is a method named mapReduce. But I'm still > uncomfortable > > with it: > > > > double total = products.mapReduce(p -> p.getPrice(), 0.0, (price, > > subTotal) -> price + subTotal); > > > > > > Regards, > > > > Francois > > > > From brian.goetz at oracle.com Mon May 21 08:54:29 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 21 May 2012 11:54:29 -0400 Subject: Question about Iterable.reduce signature In-Reply-To: References: <4FBA31DE.9070107@oracle.com> Message-ID: <4FBA6535.5010707@oracle.com> > One streaming analog to the left-fold operation is called /scan/ or > /prefix sum/[1], and there is a natural parallel analog called /parallel > prefix/[2]. A surprising number of problems can be reduced naturally to > an application of this primitive. It is natural to consider this for > the set of operations common between the lazy and parallel collection APIs. Agreed, and this is already part of the design (and partially implemented) -- see cumulate(BinaryOperator). > Cheers, > Neal > > [1] http://en.wikipedia.org/wiki/Prefix_sum > [2] > http://ocw.mit.edu/courses/mathematics/18-337j-applied-parallel-computing-sma-5505-spring-2005/lecture-notes/chapter_3.pdf > > On Mon, May 21, 2012 at 5:15 AM, Brian Goetz > wrote: > > What you are suggesting is to fuse mapping and reducing into a single > operation. While this often makes sense, the approach you suggest gets > more difficult when you want to execute in parallel. > > If you define your reducer over T as a (T,T) -> T (assuming > associativity), then to compute the reduction in parallel, you can > decompose your collection into chunks, reduce each chunk to a T, and > then reduce the reduced values up the tree until you have a single T. > > If you define your reducer as a (T,U) -> U, you can reduce each chunk to > a U, and then you have no way to combine the per-chunk Us into a single > answer. > > On 5/21/2012 2:25 AM, Fran?ois Sarradin wrote: > > Hi all, > > > > I'm looking for an answer to a question about the method reduce. > But, I > > still haven't found it in archives of the mailing list. So here is my > > question: > > > > The current signature of Iterable.reduce is: > > > > T reduce(T base, BinaryOperator reducer) > > > > I would like to know why the signature doesn't look like this one? > > > > U reduce (U base, BiOp reducer) > > > > where BiOp is supposed to represent a function of two > arguments of > > respective types T and U, that returns a value of type U. > > > > I really think that this other signature can lead to more readable > > code. Below is an example with, say, a set of products that you > want to buy > > in whatever store you want. And you want to know the total. > > > > With the current version of reduce: > > > > double total = products.map(p -> p.getPrice()).reduce(0.0, > (price, > > subTotal) -> price + subTotal); > > > > With the other version of reduce in this mail: > > > > double total = products.reduce(0.0, (p, subTotal) -> > p.getPrice() + > > subTotal); > > > > I know that there is a method named mapReduce. But I'm still > uncomfortable > > with it: > > > > double total = products.mapReduce(p -> p.getPrice(), 0.0, > (price, > > subTotal) -> price + subTotal); > > > > > > Regards, > > > > Francois > > > > From drconrad at gmail.com Tue May 22 03:09:52 2012 From: drconrad at gmail.com (David Conrad) Date: Tue, 22 May 2012 06:09:52 -0400 Subject: Note on java.util.functions Message-ID: I'm looking through java.util.functions.* and trying it out, and noticed a few things. Iterables.getFirst() and Iterators.getFirst() should throw NoSuchElementException if there are no elements, not return null, which is a perfectly valid element in some collections. Also, they should just be named first(), IMHO. The Blocks.chain() overloads that take lists or arrays of blocks claim to make defensive copies, but do not. In some of the javadoc, particularly in Blocks and Mappers, the contraction "who's" is used where possessive "whose" is wanted. Also, the wrong "its" appears. Examples: "Return a Block who's apply method does nothing.", "A mapper which who's map method returns the provided input.", "A mapper which performs a mapping from an object to it's string representation." The javadoc is garbled in the overload of Block.chain() that takes a first block and an array of blocks. The javadoc for Block's ctor says "singleton utility class", but it's not a singleton, it's a -- I don't know what you'd call it -- a nulliton? A zero-ton? :) Mappers is also not instatiable, but calls itself a singleton. Several static utility classes throw AssertionError in the ctor, but Iterables, Iterators, and ParallelIterables just throw Error. I think AssertionError should be preferred; that's what java.util.Objects uses. I know it's early days for this package, but I thought I'd mention it anyway. This is all based on the April 12 lambda build 1.8.0-ea-lambda-nightly-h140-20120412-b35-b00. Cheers, David P.S. Love throwing an AssertionError from the ctor. I hadn't thought of that before but I'm going to do that in all my static utility classes from now on. From oleksander.demura at gmail.com Tue May 22 04:05:03 2012 From: oleksander.demura at gmail.com (Olexandr Demura) Date: Tue, 22 May 2012 14:05:03 +0300 Subject: Question about Iterable.reduce signature Message-ID: Do I understand right? Point of 'reduce' accepts (T,T)->T is to have same signature T reduce(T base, Operator reducer) in unrelated hierarchies of Iterable and Splittable instead of separate U reduce((T, U)->U onNode, U onEnd) for sequential Iterable (should it be Sequence than?) U reduce((T, U, U)->U onNode, U onEnd) for parallel Splittable (should it be Tree than?) (except Splittable doesn't have marker of structure end - .iterator().hasNext() should not be) > What you are suggesting is to fuse mapping and reducing into a single > operation. While this often makes sense, the approach you suggest gets > more difficult when you want to execute in parallel. > > If you define your reducer over T as a (T,T) -> T (assuming > associativity), then to compute the reduction in parallel, you can > decompose your collection into chunks, reduce each chunk to a T, and > then reduce the reduced values up the tree until you have a single T. > > If you define your reducer as a (T,U) -> U, you can reduce each chunk to > a U, and then you have no way to combine the per-chunk Us into a single > answer. From drconrad at gmail.com Tue May 22 04:36:03 2012 From: drconrad at gmail.com (David Conrad) Date: Tue, 22 May 2012 07:36:03 -0400 Subject: Iterators.filter and remove Message-ID: It is not possible to remove an element from a collection while iterating with the iterator from java.util.Iterators.filter(). For some time now I've had a class in my personal toolkit called Filterable which is a filtered Iterable, and which allows remove when possible. It isn't likely to be at all common to remove items while iterating over a filtered collection, but there's no reason not to pass the remove call back to the upstream source, if possible. Submitted here as food for thought: package in.digo.func; import java.util.Iterator; import java.util.NoSuchElementException; public class Filterable implements Iterable { private final Iterable iterable; private final Predicate predicate; public static Iterable filter(Iterable iterable, Predicate predicate) { return new Filterable<>(iterable, predicate); } public Filterable(Iterable iterable, Predicate predicate) { this.iterable = iterable; this.predicate = predicate; } public Iterator iterator() { return new Iterator() { private Iterator source = iterable.iterator(); private boolean nextReady = false; private boolean canRemove = false; private T cache = null; @Override public boolean hasNext() { if (!nextReady) { canRemove = false; while (!nextReady && source.hasNext()) { T next = source.next(); if (predicate.accept(next)) { cache = next; nextReady = true; } } } return nextReady; } @Override public T next() { if (nextReady || hasNext()) { canRemove = true; nextReady = false; T next = cache; cache = null; return next; } throw new NoSuchElementException("no more elements"); } @Override public void remove() { if (canRemove) { source.remove(); canRemove = false; } else throw new IllegalStateException("cannot remove now"); } }; } } One other difference, besides passing along the remove call when canRemove, is the use of separate local "next" variables apart from the "cache" instance variable, and setting the latter to null before returning. This can avoid an unintentional object retention if client code, for some inexplicable reason, keeps the iterator around after removing a sought-after item. A fine point, I'll admit. Filterable is based on this Predicate, not the one in java.util.functions: package in.digo.func; public interface Predicate { boolean accept(T t); } I quite prefer accept to eval, for what it's worth. Cheers, David From brian.goetz at oracle.com Tue May 22 07:16:46 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 10:16:46 -0400 Subject: Note on java.util.functions In-Reply-To: References: Message-ID: Thanks for reviewing. > Iterables.getFirst() and Iterators.getFirst() should throw > NoSuchElementException if there are no elements, not return null, which is > a perfectly valid element in some collections. Also, they should just be > named first(), IMHO. Except that is not their intended semantics. The intended semantics is that they be find-first, where "not found" is an expected condition. One possibility for making this clearer is to return something like Guava's Option. Ultimately this comment is indicative of bad naming; obviously "getFirst" suggests to you (and probably others) that there must be a first element, maybe this should be called "findFirst" or something like that. It is made worse by the fact that getOnly *does* throw. The assymmetry is deliberate; one is a way of asserting the Iterable has exactly one element (getOnly); the other is a way of saying "get me the first one if there is any; I don't care if there are more." Both are important use cases, but probably should be named differently. > The Blocks.chain() overloads that take lists or arrays of blocks claim to > make defensive copies, but do not. These methods are likely to go away anyway. I don't think they carry their weight. > Several static utility classes throw AssertionError in the ctor, but > Iterables, Iterators, and ParallelIterables just throw Error. I think > AssertionError should be preferred; that's what java.util.Objects uses. Agreed. > I know it's early days for this package, but I thought I'd mention it > anyway. This is all based on the April 12 lambda build > 1.8.0-ea-lambda-nightly-h140-20120412-b35-b00. Thanks for reading! From brian.goetz at oracle.com Tue May 22 07:19:41 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 10:19:41 -0400 Subject: Question about Iterable.reduce signature In-Reply-To: References: Message-ID: <04D4B0DD-2CEB-48AB-A7FC-EF15FD6FF8E1@oracle.com> > Do I understand right? > Point of 'reduce' accepts (T,T)->T is to have same signature > T reduce(T base, Operator reducer) > in unrelated hierarchies of Iterable and Splittable > instead of separate > U reduce((T, U)->U onNode, U onEnd) for sequential Iterable > (should it be Sequence than?) I believe you understand it correctly. We are, at least for the time being, holding to the goal of having the same set of method names/signatures on both sequential and parallel streams. It is possible we'll be forced off this at some point, but we're going to try not to fall off without good reason. There are a number of variants of reduce/fold that may be desirable, such as one that doesn't require a base value and throws when the stream is empty. Those are in the "small fish" category for now, but we'll circle back around to whether we have the right set of reduce/fold methods at some point. From kevinb at google.com Tue May 22 07:25:29 2012 From: kevinb at google.com (Kevin Bourrillion) Date: Tue, 22 May 2012 07:25:29 -0700 Subject: Iterators.filter and remove In-Reply-To: References: Message-ID: On Tue, May 22, 2012 at 4:36 AM, David Conrad wrote: It is not possible to remove an element from a collection while iterating > with the iterator from java.util.Iterators.filter(). > The problem is that remove can only *sometimes* work. If you've called hasNext() after next() (for example because you're trying to remove the final element), it can't possibly function as expected. In Guava, we also preferred a remove that consistently is left unimplemented over one that might hide latent bugs. This also preserves the fact that hasNext() in no way changes the observable state of the iterator, which is a good thing. -- Kevin Bourrillion @ Google Java Core Libraries Team http://guava-libraries.googlecode.com From brian.goetz at oracle.com Tue May 22 07:27:10 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 10:27:10 -0400 Subject: Iterators.filter and remove In-Reply-To: References: Message-ID: <6F327510-D2AC-4498-BA64-75AAC7DE9BE8@oracle.com> > It is not possible to remove an element from a collection while iterating > with the iterator from java.util.Iterators.filter(). That's correct. > > For some time now I've had a class in my personal toolkit called Filterable > which is a filtered Iterable, and which allows remove when possible. It > isn't likely to be at all common to remove items while iterating over a > filtered collection, but there's no reason not to pass the remove call back > to the upstream source, if possible. Except for the many good reasons not to :) Stream operations are intended to be purely functional; if you want to mutate the underlying collection, there will be other methods added, such as Collections.removeIf(Predicate). Of course, we can't prevent sneaky concurrent modification, but we don't have to enscourage it. One of the nice features of this facility is the ability to do parallel operations on existing non-thread-safe collections -- you can take an ordinary ArrayList and do a parallel reduce on it. That's really nice! The price for this is non-interference -- you can't mutate the collection while you're operating on it. In reality, this restriction is not hard to comply with; non-thread-safe collections are generally thread-confined, so as long as the owning thread isn't doing anything else while a parallel op is going on, and the framework is correctly written (that's our job), this is safe. Of course, we can't prevent people from doing dumb things like mutating the collection from a Predicate or Mapper, but as I said, we don't have to encourage it. > I quite prefer accept to eval, for what it's worth. Yes, all the names are provisional. There's a strong argument for ensuring that no two standard SAM types have the same method name, though. From kevinb at google.com Tue May 22 07:32:38 2012 From: kevinb at google.com (Kevin Bourrillion) Date: Tue, 22 May 2012 07:32:38 -0700 Subject: Iterators.filter and remove In-Reply-To: <6F327510-D2AC-4498-BA64-75AAC7DE9BE8@oracle.com> References: <6F327510-D2AC-4498-BA64-75AAC7DE9BE8@oracle.com> Message-ID: On Tue, May 22, 2012 at 7:27 AM, Brian Goetz wrote: Stream operations are intended to be purely functional; if you want to > mutate the underlying collection, there will be other methods added, such > as Collections.removeIf(Predicate). > Oh. In addition to the specific things I said about a filtered iterable, this is just plain a good idea in general. -- Kevin Bourrillion @ Google Java Core Libraries Team http://guava-libraries.googlecode.com From drconrad at gmail.com Tue May 22 09:51:46 2012 From: drconrad at gmail.com (David Conrad) Date: Tue, 22 May 2012 12:51:46 -0400 Subject: Note on java.util.functions In-Reply-To: References: Message-ID: On Tue, May 22, 2012 at 10:16 AM, Brian Goetz wrote: > Thanks for reviewing. > > > Iterables.getFirst() and Iterators.getFirst() should throw > > NoSuchElementException if there are no elements, not return null, which > is > > a perfectly valid element in some collections. Also, they should just be > > named first(), IMHO. > > Except that is not their intended semantics. The intended semantics is > that they be find-first, where "not found" is an expected condition. One > possibility for making this clearer is to return something like Guava's > Option. > > Ultimately this comment is indicative of bad naming; obviously "getFirst" > suggests to you (and probably others) that there must be a first element, > maybe this should be called "findFirst" or something like that. It is made > worse by the fact that getOnly *does* throw. The assymmetry is deliberate; > one is a way of asserting the Iterable has exactly one element (getOnly); > the other is a way of saying "get me the first one if there is any; I don't > care if there are more." Both are important use cases, but probably should > be named differently. > > Ah, okay. It's partly due to their naming but also partly due to the fact that I needed something similar a short while back. But in my case I happened to want to return just the smallest (first) item in a TreeSet, and so I had: public static T first(Iterable sequence) { return sequence.iterator().next(); } and: System.out.println(first(set)); This actually came up a few times, and so when I saw getFirst() I naturally thought that's what it was. So maybe you should think about changing the name, but maybe it was just me. Cheers, David From brian.goetz at oracle.com Tue May 22 10:05:01 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 13:05:01 -0400 Subject: Note on java.util.functions In-Reply-To: References: Message-ID: <4FBBC73D.6030301@oracle.com> Either the name getFirst and getOnly are probably fine for their semantics, but the conjunction of the two is definitely confusing. I would think that getFirst/getAny should probably have "find" in their name. Its worth noting that these methods are where laziness pays off most obviously; doing a find-first on a filtered list where the filter is expensive only evalutes the filters on enough elements to find one. Summary: getFirst -- find the first element of the stream in encounter order. If none is available, return (non-exceptional) indication of same. getOnly -- get the sole element of the stream; throw an exception if the stream has zero elements or more than one element. This allows you to enforce a programmatic invariant at the same time as computing the answer. getAny -- find any element of the stream. (For sequential streams, this is likely to be identical to getFirst.) Any of these can be parallelized, to varying benefit, on finite streams. The one that shows the most parallel benefit is likely to be getAny, though for streams involving highly selective filters or expensive per-element computation, getFirst/getOnly may well show some speedup. On 5/22/2012 12:51 PM, David Conrad wrote: > > > On Tue, May 22, 2012 at 10:16 AM, Brian Goetz > wrote: > > Thanks for reviewing. > > > Iterables.getFirst() and Iterators.getFirst() should throw > > NoSuchElementException if there are no elements, not return null, > which is > > a perfectly valid element in some collections. Also, they should > just be > > named first(), IMHO. > > Except that is not their intended semantics. The intended semantics > is that they be find-first, where "not found" is an expected > condition. One possibility for making this clearer is to return > something like Guava's Option. > > Ultimately this comment is indicative of bad naming; obviously > "getFirst" suggests to you (and probably others) that there must be > a first element, maybe this should be called "findFirst" or > something like that. It is made worse by the fact that getOnly > *does* throw. The assymmetry is deliberate; one is a way of > asserting the Iterable has exactly one element (getOnly); the other > is a way of saying "get me the first one if there is any; I don't > care if there are more." Both are important use cases, but probably > should be named differently. > > > Ah, okay. It's partly due to their naming but also partly due to the > fact that I needed something similar a short while back. But in my case > I happened to want to return just the smallest (first) item in a > TreeSet, and so I had: > > public static T first(Iterable sequence) { > return sequence.iterator().next(); > } > > and: > > System.out.println(first(set)); > > This actually came up a few times, and so when I saw getFirst() I > naturally thought that's what it was. So maybe you should think about > changing the name, but maybe it was just me. > > Cheers, > David > From Klaus.Malorny at knipp.de Tue May 22 11:33:50 2012 From: Klaus.Malorny at knipp.de (Klaus Malorny) Date: Tue, 22 May 2012 20:33:50 +0200 Subject: Note on java.util.functions In-Reply-To: <4FBBC73D.6030301@oracle.com> References: <4FBBC73D.6030301@oracle.com> Message-ID: <4FBBDC0E.4000205@knipp.de> On 22/05/12 19:05, Brian Goetz wrote: > > Summary: > > getFirst -- find the first element of the stream in encounter order. If > none is available, return (non-exceptional) indication of same. > > getOnly -- get the sole element of the stream; throw an exception if the > stream has zero elements or more than one element. This allows you to > enforce a programmatic invariant at the same time as computing the answer. > > getAny -- find any element of the stream. (For sequential streams, this > is likely to be identical to getFirst.) > > Any of these can be parallelized, to varying benefit, on finite streams. > The one that shows the most parallel benefit is likely to be getAny, > though for streams involving highly selective filters or expensive > per-element computation, getFirst/getOnly may well show some speedup. > Hi Brian, please feel free to ignore, but I as a non-native speaker feel a bit lost about the semantics when I read the method name "getOnly". Have you considered an alternative name, for example "getSingle"? Regards, Klaus From drconrad at gmail.com Tue May 22 11:37:43 2012 From: drconrad at gmail.com (David Conrad) Date: Tue, 22 May 2012 14:37:43 -0400 Subject: Iterable::forEach not returning Iterable Message-ID: On Thu, 17 May 2012 12:33:59 +0200, Tomasz Kowalczewski < tomasz.kowalczewski at gmail.com> wrote: > ... while doing some simple towards-lambda-refactoring I stumbled on: > > List files... > files.filter( File::isFile ).filter( ... ).map( ConfigurationFile::new ); > > I wanted to inject some debugging code inside this chain using forEach > and realized that it returns void and not Iterable. > On Thu, 17 May 2012 16:31:40 +0200, R?mi Forax wrote: > On 05/17/2012 04:05 PM, Brian Goetz wrote: > > Of course, no one would write production code like this. Mappers are > > supposed to be side-effect-free. But it is an acceptable sin for > > temporary debugging code. > > Haskell guys, please don't read ... > > but logging is side effect free until you read the log in the program. > That's what I say, too, but they never listen ! > R?mi > > > > > On 5/17/2012 9:26 AM, Remi Forax wrote: > >> You can use > >> map(it -> { > >> Log.log(it); > >> return it; > >> }). > >> instead of forEach. > >> > >> R?mi > >> > If you use it often, a little helper method may make it easier to read: public static Mapper tee(Block block) { return t -> { block.apply(t); return t; }; } And then Thomasz's example becomes: List files... files.filter( File::isFile ).map(tee((File f) -> { Log.log(f); return f; })).filter( ... ).map( ConfigurationFile::new ); I had to qualify the type of the lambda parameter, though; the compiler couldn't infer it. Ah, well. Cheers, R?mi ! David From brian.goetz at oracle.com Tue May 22 11:45:45 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 14:45:45 -0400 Subject: Note on java.util.functions In-Reply-To: <4FBBDC0E.4000205@knipp.de> References: <4FBBC73D.6030301@oracle.com> <4FBBDC0E.4000205@knipp.de> Message-ID: <4FBBDED9.9020600@oracle.com> Yes, naming is still up in the air. First nailing down semantics... On 5/22/2012 2:33 PM, Klaus Malorny wrote: > On 22/05/12 19:05, Brian Goetz wrote: >> >> Summary: >> >> getFirst -- find the first element of the stream in encounter order. If >> none is available, return (non-exceptional) indication of same. >> >> getOnly -- get the sole element of the stream; throw an exception if the >> stream has zero elements or more than one element. This allows you to >> enforce a programmatic invariant at the same time as computing the answer. >> >> getAny -- find any element of the stream. (For sequential streams, this >> is likely to be identical to getFirst.) >> >> Any of these can be parallelized, to varying benefit, on finite streams. >> The one that shows the most parallel benefit is likely to be getAny, >> though for streams involving highly selective filters or expensive >> per-element computation, getFirst/getOnly may well show some speedup. >> > > Hi Brian, > > please feel free to ignore, but I as a non-native speaker feel a bit lost about > the semantics when I read the method name "getOnly". Have you considered an > alternative name, for example "getSingle"? > > Regards, > > Klaus > > From adam.hawthorne at gmail.com Tue May 22 13:01:20 2012 From: adam.hawthorne at gmail.com (Adam Hawthorne) Date: Tue, 22 May 2012 16:01:20 -0400 Subject: Logging API Message-ID: I don't know if it's premature to discuss non-Collections APIs, but in trying out Lambda, I encountered problems using java.util.logging.Logger. Here's some sample code: import static java.util.logging.Level.INFO; import static LambdaTest.Stringifier._; import java.util.concurrent.Callable; import java.util.logging.Logger; public class LambdaTest { public static void main(String... argv) { // Fails to compile, no suitable method // Logger.getAnonymousLogger().log(INFO, "Hello {0}", () -> "World"); // Fails to compile, java.lang.Object method restrictions // ToString arg1 = () -> "World"; // Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg1); // Does not produce "hoped for" output, Callable.get() isn't the same as toString() Callable arg2 = () -> "World"; Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg2); // Does not produce "hoped for" output, Object.toString() is defined. Stringer arg3 = () -> "World"; Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg3); // Works, but hokey/extra allocation Logger.getAnonymousLogger().log(INFO, "Hello {0}", _(() -> "World")); } public interface ToString { String toString(); } public interface Stringer { String string(); String toString() default { return string(); } } public static class Stringifier { private final Callable val; public Stringifier(Callable val) { this.val = val; } @Override public String toString() { try { return val.call(); } catch (Exception e) { throw new RuntimeException(e); } } public static Stringifier _(Callable val) { return new Stringifier(val); } } } One of the nice things about the logging API is that it doesn't actually invoke toString() on the arguments unless the log level is actually enabled. Lambdas are obvious choices for this kind of delayed execution, but I tried to do battle against Logging and I lost. It seems to me that option 4 should work, although I understand from Defenders section 3, Object.toString() takes precedence over the defender toString() in Stringer. It would be helpful if using the Logging API was more friendly towards Lambdas. Adam From maurizio.cimadamore at oracle.com Tue May 22 13:13:19 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 22 May 2012 21:13:19 +0100 Subject: Iterable::forEach not returning Iterable In-Reply-To: References: Message-ID: <4FBBF35F.3040107@oracle.com> On 22/05/12 19:37, David Conrad wrote: > List files... > files.filter( File::isFile ).map(tee((File f) -> { Log.log(f); return f; > })).filter( ... ).map( ConfigurationFile::new ); > > I had to qualify the type of the lambda parameter, though; the compiler > couldn't infer it. Ah, well. RIght, because the prototype doesn't support nested generic method call, so the call to tee nested into map yields Object for T - but stay tuned, as a solution is in the works ;-) Maurizio From brian.goetz at oracle.com Tue May 22 13:17:08 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 16:17:08 -0400 Subject: Logging API In-Reply-To: References: Message-ID: <4FBBF444.3080608@oracle.com> Yes, some time ago we ran a "point lambdafication" survey on this list, and this was the #1 suggestion. So rest assured, it is on the list of ideas. I'd also note that the primary goal of such a change is performance, and the story there isn't as perfect as you might prefer. Capturing a lambda which captures variables from the enclosing scope has a cost, comparable to an object allocation. (On the other hand, capturing non-capturing lambdas, which will be the common case for many filter/map/reduce type of operations, should be basically free.) So while you defer creating the string until you need it, you do not necessarily defer creating the lambda (though the VM may be able to optimize that away in some cases.) So the "Factory approach" will be faster than just precomputing the string unconditionally, but probably slower than the commonly used trick of preceding the logging call with an "if (logger.level() >= DEBUG)" statement. So if you were thinking this would be a totally free way to replace those ugly if statements, you might be disappointed. Of course, there's lots the VM might do to help in the future. But that's the future. On 5/22/2012 4:01 PM, Adam Hawthorne wrote: > I don't know if it's premature to discuss non-Collections APIs, but in > trying out Lambda, I encountered problems using java.util.logging.Logger. > Here's some sample code: > > > import static java.util.logging.Level.INFO; > import static LambdaTest.Stringifier._; > > import java.util.concurrent.Callable; > import java.util.logging.Logger; > > public class LambdaTest { > public static void main(String... argv) { > // Fails to compile, no suitable method > // Logger.getAnonymousLogger().log(INFO, "Hello {0}", () -> "World"); > > // Fails to compile, java.lang.Object method restrictions > // ToString arg1 = () -> "World"; > // Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg1); > > // Does not produce "hoped for" output, Callable.get() > isn't the same as toString() > Callable arg2 = () -> "World"; > Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg2); > > // Does not produce "hoped for" output, Object.toString() is > defined. > Stringer arg3 = () -> "World"; > Logger.getAnonymousLogger().log(INFO, "Hello {0}", arg3); > > // Works, but hokey/extra allocation > Logger.getAnonymousLogger().log(INFO, "Hello {0}", _(() -> > "World")); > } > > public interface ToString { > String toString(); > } > > public interface Stringer { > String string(); > > String toString() default { > return string(); > } > } > > public static class Stringifier { > private final Callable val; > > public Stringifier(Callable val) { > this.val = val; > } > > @Override > public String toString() { > try { > return val.call(); > } catch (Exception e) { > throw new RuntimeException(e); > } > } > > public static Stringifier _(Callable val) { > return new Stringifier(val); > } > } > } > > One of the nice things about the logging API is that it doesn't actually > invoke toString() on the arguments unless the log level is actually > enabled. Lambdas are obvious choices for this kind of delayed execution, > but I tried to do battle against Logging and I lost. > > It seems to me that option 4 should work, although I understand from > Defenders section 3, Object.toString() takes precedence over the defender > toString() in Stringer. It would be helpful if using the Logging API was > more friendly towards Lambdas. > > Adam > From adam.hawthorne at gmail.com Tue May 22 13:38:09 2012 From: adam.hawthorne at gmail.com (Adam Hawthorne) Date: Tue, 22 May 2012 16:38:09 -0400 Subject: Logging API In-Reply-To: <4FBBF444.3080608@oracle.com> References: <4FBBF444.3080608@oracle.com> Message-ID: On Tue, May 22, 2012 at 4:17 PM, Brian Goetz wrote: > Yes, some time ago we ran a "point lambdafication" survey on this list, > and this was the #1 suggestion. So rest assured, it is on the list of > ideas. > Thanks for the reassurance. > > I'd also note that the primary goal of such a change is performance, and > the story there isn't as perfect as you might prefer. Capturing a lambda > which captures variables from the enclosing scope has a cost, comparable to > an object allocation. (On the other hand, capturing non-capturing lambdas, > which will be the common case for many filter/map/reduce type of > operations, should be basically free.) So while you defer creating the > string until you need it, you do not necessarily defer creating the lambda > (though the VM may be able to optimize that away in some cases.) So the > "Factory approach" will be faster than just precomputing the string > unconditionally, but probably slower than the commonly used trick of > preceding the logging call with an "if (logger.level() >= DEBUG)" > statement. So if you were thinking this would be a totally free way to > replace those ugly if statements, you might be disappointed. > The log(Level, String, Object) method in the Oracle JDK does as its first statement: if (level.intValue() < levelValue || levelValue == offValue) { return; } I think Hotspot is currently able to inline that method. It also seems like allocating a lambda should be side-effect free. If so, might we expect the VM to be smart enough in JDK 8 to know that it can push the allocation inside that 'if' (assuming it's not used for anything else)? Adam > Of course, there's lots the VM might do to help in the future. But that's > the future. > > > > On 5/22/2012 4:01 PM, Adam Hawthorne wrote: > >> I don't know if it's premature to discuss non-Collections APIs, but in >> trying out Lambda, I encountered problems using java.util.logging.Logger. >> Here's some sample code: >> >> >> import static java.util.logging.Level.INFO; >> import static LambdaTest.Stringifier._; >> >> import java.util.concurrent.Callable; >> import java.util.logging.Logger; >> >> public class LambdaTest { >> public static void main(String... argv) { >> // Fails to compile, no suitable method >> // Logger.getAnonymousLogger().**log(INFO, "Hello {0}", () -> >> "World"); >> >> // Fails to compile, java.lang.Object method restrictions >> // ToString arg1 = () -> "World"; >> // Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg1); >> >> // Does not produce "hoped for" output, Callable.get() >> isn't the same as toString() >> Callable arg2 = () -> "World"; >> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg2); >> >> // Does not produce "hoped for" output, Object.toString() is >> defined. >> Stringer arg3 = () -> "World"; >> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", arg3); >> >> // Works, but hokey/extra allocation >> Logger.getAnonymousLogger().**log(INFO, "Hello {0}", _(() -> >> "World")); >> } >> >> public interface ToString { >> String toString(); >> } >> >> public interface Stringer { >> String string(); >> >> String toString() default { >> return string(); >> } >> } >> >> public static class Stringifier { >> private final Callable val; >> >> public Stringifier(Callable val) { >> this.val = val; >> } >> >> @Override >> public String toString() { >> try { >> return val.call(); >> } catch (Exception e) { >> throw new RuntimeException(e); >> } >> } >> >> public static Stringifier _(Callable val) { >> return new Stringifier(val); >> } >> } >> } >> >> One of the nice things about the logging API is that it doesn't actually >> invoke toString() on the arguments unless the log level is actually >> enabled. Lambdas are obvious choices for this kind of delayed execution, >> but I tried to do battle against Logging and I lost. >> >> It seems to me that option 4 should work, although I understand from >> Defenders section 3, Object.toString() takes precedence over the defender >> toString() in Stringer. It would be helpful if using the Logging API was >> more friendly towards Lambdas. >> >> Adam >> >> -- "... that I may know Him and the power of His resurrection, and the fellowship of His sufferings, being conformed to His death, if, by any means, I may attain to the resurrection from the dead." From brian.goetz at oracle.com Tue May 22 13:48:05 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 May 2012 16:48:05 -0400 Subject: Logging API In-Reply-To: References: <4FBBF444.3080608@oracle.com> Message-ID: <4FBBFB85.1010902@oracle.com> > I'd also note that the primary goal of such a change is performance, > and the story there isn't as perfect as you might prefer. Capturing > a lambda which captures variables from the enclosing scope has a > cost, comparable to an object allocation. (On the other hand, > capturing non-capturing lambdas, which will be the common case for > many filter/map/reduce type of operations, should be basically > free.) So while you defer creating the string until you need it, > you do not necessarily defer creating the lambda (though the VM may > be able to optimize that away in some cases.) So the > "Factory approach" will be faster than just precomputing the > string unconditionally, but probably slower than the commonly used > trick of preceding the logging call with an "if (logger.level() >= > DEBUG)" statement. So if you were thinking this would be a totally > free way to replace those ugly if statements, you might be disappointed. > > The log(Level, String, Object) method in the Oracle JDK does as its > first statement: > > if (level.intValue() < levelValue || levelValue == offValue) { > return; > } > > I think Hotspot is currently able to inline that method. It also seems > like allocating a lambda should be side-effect free. If so, might we > expect the VM to be smart enough in JDK 8 to know that it can push the > allocation inside that 'if' (assuming it's not used for anything else)? HotSpot is certainly *able* to inline the method. There is no guarantee that it will *always* inline the method. If it does not, the capture costs will have to be paid regardless of use. Assume it inlines the method. It does indeed seem that allocating a lambda should be side-effect free. It is also easy for HotSpot to recognize lambda captures in the bytecode (they are invokedynamic call sites with a well-known bootstrap method.) We certainly do intend to make the VM smart enough to know this, which would allow code motion so as to push the capture until the latest possible time (into the "if"), and, if escape analysis says it is OK, to do "box elision" on the lambda object and turn the virtual method invocation into a direct MH invocation on the underlying desugared lambda body, and then optimize away the lambda capture entirely. Which would be pretty close to free. Would we like to do that? Of course. Do we know how? Yes. Can we do it for JDK 8, with our current resourcing situation and current and future competing priorities? Can't say. Let's just say it's not guaranteed that all the possible optimizations we'd like to do will be done for JDK 8, which motivated my caveats about the performance characteristics of the idiom you were requesting, just in case you might have been under the impression that it would be free and wanting to save you some disappointment. From john.r.rose at oracle.com Tue May 22 16:06:15 2012 From: john.r.rose at oracle.com (John Rose) Date: Tue, 22 May 2012 16:06:15 -0700 Subject: Logging API In-Reply-To: References: <4FBBF444.3080608@oracle.com> Message-ID: <77CD3453-56CD-4F7D-9038-6CEEC586CA47@oracle.com> On May 22, 2012, at 1:38 PM, Adam Hawthorne wrote: > I think Hotspot is currently able to inline that method. It also seems > like allocating a lambda should be side-effect free. If so, might we > expect the VM to be smart enough in JDK 8 to know that it can push the > allocation inside that 'if' (assuming it's not used for anything else)? This question made me curious. In the Hotspot JVM we have various bits of escape analysis, etc., but there is always a question of what happens in some specific use case. I tried a few use case combinations and noted the results in this file: https://blogs.oracle.com/jrose/resource/code/EALogTest.zip I got the usual answer. The JVM can optimize some use cases but not all, and will require more work to optimize a wider variety of cases. One bright spot: Closures (or simple "message objects") will optimize better than random formatted strings. One dim spot: You currently have to use "static final" configuration variables, or the compiler will assume you might decide to log something at any moment. (I'm going back to lurk mode now.) ? John P.S. Here's the whole file. /* Demonstration of optimization of a log-like API. Requires constant (static final) log level setting, or else "as if final" stable value optimization. Requires simple (not StringBuffer) object message argument to log function. Test cases: $ java -DLOG_LEVEL=0 EALogTest # hello() optimizes to null routine $ java -DLOG_LEVEL=1 EALogTest # hello() builds a simple Greeting, and queues it $ java -DLOG_EXCITEMENT=1 EALogTest # hello() does StringBuffer stuff, and throws it away $ java -DLOG_{LEVEL,EXCITEMENT}=1 EALogTest # hello() does StringBuffer stuff, and queues it To observe the object code, put hsdis-amd64.{dll,so,dylib} on your LLP and: $ java -XX:CompileCommand=print,EALogTest.hello -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+Print{Compilation,Inlining} -XX:+LogCompilation EALogTest Ref: https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly Conclusion: Hotspot JVM has sufficient if limited EA capability to remove unused log message construction, if log switch is "static final", and if the log messages are simple objects (lambdas should work). Desirable future work: - optimistically constant-fold stable values (as if they were declared final) until they change - allow side-effect-free object creation code to move down past an 'if', if it is dead on one branch - eliminate string formatting code if it goes unused */ class EALogTest { public static void main(String... av) { System.out.println("Preparing greetings... (L/E="+LOG_LEVEL+"/"+LOG_EXCITEMENT+")"); helloStorm("City", 100000); helloStorm("State", 100000); maybeChangeLogLevel(); helloStorm("World", 100000); } static void maybeChangeLogLevel() { if (LOG_LEVEL == 1) return; //LOG_LEVEL = 1; try { java.lang.reflect.Field LOG_LEVEL = EALogTest.class.getDeclaredField("LOG_LEVEL"); if ((java.lang.reflect.Modifier.FINAL & LOG_LEVEL.getModifiers()) == 0) { LOG_LEVEL.setInt(null, 1); System.out.println("set LOG_LEVEL to 1"); } else { System.out.println("cannot set LOG_LEVEL (it is final)"); } } catch (Exception ex) { throw new RuntimeException("cannot touch LOG_LEVEL!", ex); } } static void helloStorm(String who, int count) { for (int i = 0; i < count; i++) hello(who); } static void hello(String who) { if (LOG_EXCITEMENT > 0) // Much harder to EA! logMsg("HELLO, "+who); else logMsg(new Greeting(who)); } static class Greeting { final String who; Greeting(String who) { this.who = who; } public String toString() { who.toString(); return "Hello, "+who; } } static void logMsg(Object msg) { if (LOG_LEVEL > 0) { int ptr = LOG_SINK_PTR + 1; if (ptr == 0) System.out.println(msg); if (ptr == LOG_SINK.length) ptr = 0; LOG_SINK[LOG_SINK_PTR = ptr] = msg; } } static final // this modifier is important, pending JVM optimizations for stable values int LOG_LEVEL = Integer.parseInt(System.getProperty("LOG_LEVEL", "0")); static final int LOG_EXCITEMENT = Integer.parseInt(System.getProperty("LOG_EXCITEMENT", "0")); static Object[] LOG_SINK = new Object[100]; static int LOG_SINK_PTR = -1; } From neal at gafter.com Wed May 23 08:55:28 2012 From: neal at gafter.com (Neal Gafter) Date: Wed, 23 May 2012 08:55:28 -0700 Subject: Note on java.util.functions In-Reply-To: <4FBBDED9.9020600@oracle.com> References: <4FBBC73D.6030301@oracle.com> <4FBBDC0E.4000205@knipp.de> <4FBBDED9.9020600@oracle.com> Message-ID: On Tue, May 22, 2012 at 11:45 AM, Brian Goetz wrote: > Yes, naming is still up in the air. First nailing down semantics... Are you planning to synchronize the naming with the work of jsr341, which calls this method singleOrDefault()? 2.3.32 singleOrDefault Operator The singleOrDefault operator returns the single element of a collection, or a default value of null if no element is found. 2.3.32.1 Syntax S Iterable.singleOrDefault() S Iterable.singleOrDefaultOrDefault((S->boolean) predicate) From drconrad at gmail.com Wed May 23 09:20:44 2012 From: drconrad at gmail.com (David Conrad) Date: Wed, 23 May 2012 12:20:44 -0400 Subject: Iterable::forEach not returning Iterable In-Reply-To: <4FBBF35F.3040107@oracle.com> References: <4FBBF35F.3040107@oracle.com> Message-ID: On Tue, May 22, 2012 at 4:13 PM, Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > On 22/05/12 19:37, David Conrad wrote: > >> List files... >> files.filter( File::isFile ).map(tee((File f) -> { Log.log(f); return f; >> })).filter( ... ).map( ConfigurationFile::new ); >> >> I had to qualify the type of the lambda parameter, though; the compiler >> couldn't infer it. Ah, well. >> > RIght, because the prototype doesn't support nested generic method call, > so the call to tee nested into map yields Object for T - but stay tuned, as > a solution is in the works ;-) > > Maurizio > Good news. :) I hope it will also clear up this case, which I'm sure you're already aware of (this is with the May 11 lambda build): import java.util.Set; import java.util.TreeSet; import static java.util.Arrays.iterable; public class Setty { public static void main(String[] args) { Set s = iterable(args).map(Integer::new).into(new TreeSet<>()); System.out.println(s); } } dconrad at darwin ~/src/java $ javac Setty.java Setty.java:8: error: incompatible types iterable(args).map(Integer::new).into(new TreeSet<>()); ^ required: Set found: TreeSet 1 error "I know what you meant, but I want to hear you say it." :) Cheers, David From oleksander.demura at gmail.com Wed May 23 09:21:43 2012 From: oleksander.demura at gmail.com (Olexandr Demura) Date: Wed, 23 May 2012 19:21:43 +0300 Subject: default methods reuse in Proxy Message-ID: Is it possible to call default implementation of method for Proxy? So far default`ed methods handled thru InvocationHandler as well even they are not marked abstract. I do not see which way can default implementation be called, since: - their `getDefaultValue()` gives `null`, unlike @annotation's. - there is no additional statics method in class w/ added first parameter for `this`. Is it planned to hide or will be changed to be accessible? BTW, why we still need to write `default`? especially since only in-line defaulting style is supported now. From brian.goetz at oracle.com Wed May 23 10:04:00 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 23 May 2012 13:04:00 -0400 Subject: Note on java.util.functions In-Reply-To: References: <4FBBC73D.6030301@oracle.com> <4FBBDC0E.4000205@knipp.de> <4FBBDED9.9020600@oracle.com> Message-ID: <4FBD1880.2090107@oracle.com> JSR-341 introduces a static-extension-method-like mechanism into EL, but EL has nothing to do with the Java language or libraries. Think of EL/JSR-341 as just another scripting language. We can't possibly align the Java language and libraries with all the scripting languages that will be built on top of the JVM, nor would we want to. On 5/23/2012 11:55 AM, Neal Gafter wrote: > On Tue, May 22, 2012 at 11:45 AM, Brian Goetz > wrote: > > Yes, naming is still up in the air. First nailing down semantics... > > > Are you planning to synchronize the naming with the work of jsr341, > which calls this method singleOrDefault()? > > 2.3.32 singleOrDefault Operator > The singleOrDefault operator returns the single element of a collection, > or a default value of null if no element is found. > 2.3.32.1 Syntax > S Iterable.singleOrDefault() > S Iterable.singleOrDefaultOrDefault((S->boolean) predicate) > From brian.goetz at oracle.com Wed May 23 14:04:55 2012 From: brian.goetz at oracle.com (brian.goetz at oracle.com) Date: Wed, 23 May 2012 21:04:55 +0000 Subject: hg: lambda/lambda/jdk: Improvements to combo-test framework to support separate compilation. Message-ID: <20120523210534.B7B36474A7@hg.openjdk.java.net> Changeset: 17b626c102d6 Author: briangoetz Date: 2012-05-23 17:04 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/17b626c102d6 Improvements to combo-test framework to support separate compilation. ! combo-tests/tests/tools/javac/combo/ComboTestBase.java ! combo-tests/tests/tools/javac/combo/JavacTemplateTestBase.java + combo-tests/tests/tools/javac/combo/SeparateCompilationComboTest2.java From pbenedict at apache.org Wed May 23 14:13:25 2012 From: pbenedict at apache.org (Paul Benedict) Date: Wed, 23 May 2012 16:13:25 -0500 Subject: Defaults methods and Remoting Message-ID: The answer may be simple, but just wanted to throw this question out there. Business interfaces on Remote EJBs are necessary. What would happen if an interface evolved with default methods, but the default implementation only existed on the remoted end? I imagine an exception from the client's ClassLoader. I am curious if evolving interfaces and remoting are compatible or mutually exclusive. Paul From takeshi10 at gmail.com Wed May 23 14:24:57 2012 From: takeshi10 at gmail.com (Takeshi Fukushima) Date: Wed, 23 May 2012 18:24:57 -0300 Subject: Defaults methods and Remoting In-Reply-To: References: Message-ID: could that happen? i mean... if the client isnt compiled with the new interface (with the new default'ed methods), how can he call the new methods and thus trigger the error? i'd say either the proxy forwards the method to the remote object (which i think it's what is suppose to happen) or the proxy itself executes the body of the method based on 'this' - the proxy itself (which, in turn, may call remote methods) we may generalize the question to: what happens to proxies when the proxied interface has default implementation of methods? do those get forwarded to the InvocationHandler? On Wed, May 23, 2012 at 6:13 PM, Paul Benedict wrote: > The answer may be simple, but just wanted to throw this question out there. > > Business interfaces on Remote EJBs are necessary. What would happen if an > interface evolved with default methods, but the default implementation only > existed on the remoted end? I imagine an exception from the client's > ClassLoader. I am curious if evolving interfaces and remoting are > compatible or mutually exclusive. > > Paul > > -- http://mapsdev.blogspot.com/ Marcelo Takeshi Fukushima From drconrad at gmail.com Wed May 23 15:28:35 2012 From: drconrad at gmail.com (David Conrad) Date: Wed, 23 May 2012 18:28:35 -0400 Subject: Compilation yields no class files, no errors Message-ID: I ran into something weird with the May 11 lambda build this afternoon. The compiler exited normally, but generated no class files. No errors. The simplest case I've been able to get it down to: Here's TextFile.java: interface Read { T read(T value, String line); } interface Lines { void read(String line, int number); } interface Liner { T read(T value, String line, int number); } public class TextFile { private final java.util.List list; private final T initial; public TextFile(final java.util.List list, final T initial) { this.list = list; this.initial = initial; } public T read(Read reader) { return read((t, s, i) -> { return reader.read(t, s); }); } public void read(Lines reader) { read((t, s, i) -> { reader.read(s, i); return t; }); } public T read(Liner reader) { int number = 0; T value = initial; for (String line : list) { value = reader.read(value, line, ++number); } return value; } } TextFile.java compiles okay. Problem.java doesn't, unless I uncomment /*, number*/: public class Problem { public static void main(String[] args) { java.util.List list = java.util.Arrays.asList(args); TextFile textfile = new TextFile<>(list, new StringBuilder()); StringBuilder sb = textfile.read((builder, string/*, number*/) -> { if ("good".equals(string)) { //System.out.println("line " + number + " matches"); builder.append(string); } return builder; }); System.out.println(sb); } } Also, Problem.java compiles, even without the third parameter to the lambda, if I eliminate interface Lines from TextFile.java. So, I thought it was getting confused between the two functional interfaces that both take two parameters. But adding explicit types to the lambda parameters in Problem.java doesn't help. The compiler runs, exits with status 0, but no class files. I tried compiling with javac -Xlint:all -verbose Problem.java, but it looks just like it should, except there are no [wrote RegularFileObject[*.class]] lines. Unfortunately, that's all the compiler-fu I possess. Is this a bug, or is my environment hosed somehow? I didn't build it, I'm using the 64-bit windows build of May 11 from jdk8.java.net/lambda. Perplexed, David (It all started with a funny class that was going to take a lambda and call it for every line of a text file, modulo a few overloads, if you're wondering.) From fsarradin at gmail.com Wed May 23 21:53:58 2012 From: fsarradin at gmail.com (=?ISO-8859-1?Q?Fran=E7ois_Sarradin?=) Date: Thu, 24 May 2012 06:53:58 +0200 Subject: Iterable.zipWith Message-ID: Hi, What do you think about adding a kind of zip or zipWith method to the Iterable interface? As a reminder, zipWith is a method that mixes two Iterables with a function in a view to produce a third Iterable. More exactly, zipWith takes elements of two Iterables one by one and applies a function on them in order to produce the elements of the third Iterable. In a sense, it is the inverse operation of tee. Notice that the resulting Iterable has as many elements as the smallest Iterable. For example, this is the way you would compose the methods zipWith and reduce to have a dot product operator: Iterable u = Arrays.asList(1.0, 2.0, 3.0); Iterable v = Arrays.asList(4.0, 5.0, 6.0); double dotProduct = u.zipWith(v, (x, y) -> x * y).reduce(0.0, (x, y) -> x + y); assertEquals(32.0, dotProduct, 1e-7); zipWith is specifically a lazy method. Each element of the result can be evaluated independently from the other ones. A signature for zipWith in Iterables might be: Iterable zipWith(Iterable elements1, Iterable elements2, BiMapper biMapper) Regards, fran?ois- From brian.goetz at oracle.com Wed May 23 22:49:24 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 24 May 2012 01:49:24 -0400 Subject: Iterable.zipWith In-Reply-To: References: Message-ID: <4FBDCBE4.5070105@oracle.com> Yes, we've discussed zip operations that would produce a BiStream. Straightforward enough, just hasn't come near the top of the list yet. On 5/24/2012 12:53 AM, Fran?ois Sarradin wrote: > Hi, > > What do you think about adding a kind of zip or zipWith method to the > Iterable interface? > > As a reminder, zipWith is a method that mixes two Iterables with a function > in a view to produce a third Iterable. More exactly, zipWith takes elements > of two Iterables one by one and applies a function on them in order to > produce the elements of the third Iterable. In a sense, it is the inverse > operation of tee. Notice that the resulting Iterable has as many elements > as the smallest Iterable. > > For example, this is the way you would compose the methods zipWith and > reduce to have a dot product operator: > > Iterable u = Arrays.asList(1.0, 2.0, 3.0); > Iterable v = Arrays.asList(4.0, 5.0, 6.0); > > double dotProduct = u.zipWith(v, (x, y) -> x * y).reduce(0.0, (x, > y) -> x + y); > > assertEquals(32.0, dotProduct, 1e-7); > > > zipWith is specifically a lazy method. Each element of the result can be > evaluated independently from the other ones. > > A signature for zipWith in Iterables might be: > > Iterable zipWith(Iterable elements1, Iterable > elements2, BiMapper biMapper) > > > Regards, > > fran?ois- > From maurizio.cimadamore at oracle.com Thu May 24 03:34:32 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Thu, 24 May 2012 10:34:32 +0000 Subject: hg: lambda/lambda/langtools: Fix: Stale state after speculative attribution round leads to missing classfiles Message-ID: <20120524103437.C4A9C474BE@hg.openjdk.java.net> Changeset: 789f882404a9 Author: mcimadamore Date: 2012-05-24 11:33 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/789f882404a9 Fix: Stale state after speculative attribution round leads to missing classfiles ! src/share/classes/com/sun/tools/javac/comp/Attr.java + test/tools/javac/lambda/ErroneousLambdaExpr.java From maurizio.cimadamore at oracle.com Thu May 24 03:35:22 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 24 May 2012 11:35:22 +0100 Subject: Compilation yields no class files, no errors In-Reply-To: References: Message-ID: <4FBE0EEA.8080702@oracle.com> Fixed in the lambda repository. Thanks for the report Maurizio On 23/05/12 23:28, David Conrad wrote: > I ran into something weird with the May 11 lambda build this afternoon. > The compiler exited normally, but generated no class files. No errors. > > The simplest case I've been able to get it down to: Here's TextFile.java: > > interface Read { > T read(T value, String line); > } > > interface Lines { > void read(String line, int number); > } > > interface Liner { > T read(T value, String line, int number); > } > > public class TextFile { > private final java.util.List list; > private final T initial; > > public TextFile(final java.util.List list, final T initial) { > this.list = list; > this.initial = initial; > } > > public T read(Read reader) { > return read((t, s, i) -> { return reader.read(t, s); }); > } > > public void read(Lines reader) { > read((t, s, i) -> { reader.read(s, i); return t; }); > } > > public T read(Liner reader) { > int number = 0; > T value = initial; > for (String line : list) { > value = reader.read(value, line, ++number); > } > return value; > } > } > > TextFile.java compiles okay. Problem.java doesn't, unless I uncomment /*, > number*/: > > public class Problem { > public static void main(String[] args) { > java.util.List list = java.util.Arrays.asList(args); > > TextFile textfile = > new TextFile<>(list, new StringBuilder()); > > StringBuilder sb = > textfile.read((builder, string/*, number*/) -> { > if ("good".equals(string)) { > //System.out.println("line " + number + " matches"); > builder.append(string); > } > return builder; > }); > > System.out.println(sb); > } > } > > Also, Problem.java compiles, even without the third parameter to the lambda, > if I eliminate interface Lines from TextFile.java. So, I thought it was > getting > confused between the two functional interfaces that both take two > parameters. > But adding explicit types to the lambda parameters in Problem.java doesn't > help. The compiler runs, exits with status 0, but no class files. > > I tried compiling with javac -Xlint:all -verbose Problem.java, but it looks > just > like it should, except there are no [wrote RegularFileObject[*.class]] > lines. > Unfortunately, that's all the compiler-fu I possess. > > Is this a bug, or is my environment hosed somehow? I didn't build it, I'm > using the 64-bit windows build of May 11 from jdk8.java.net/lambda. > > Perplexed, > David > > (It all started with a funny class that was going to take a lambda and call > it for every line of a text file, modulo a few overloads, if you're > wondering.) > From maurizio.cimadamore at oracle.com Thu May 24 06:37:38 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Thu, 24 May 2012 13:37:38 +0000 Subject: hg: lambda/lambda/langtools: Lambda attribution overhaul. Message-ID: <20120524133742.AC68D474C3@hg.openjdk.java.net> Changeset: 314e550e28af Author: mcimadamore Date: 2012-05-24 14:35 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/314e550e28af Lambda attribution overhaul. *) consistent use of target-typing *) nested generic method call support *) diamond in method context support *) conditional in method context support *) better diagnostic generation for erroneous poly expressions *) entirely rewritten logic for supporting speculative attribution (see DeferredAttr) *) out-of-order method checking support *) improvements in inference infrastructure *) dropped PolyType class *) dropped usage of ForAll for partially instantiated method types *) dropped extra method check to verify correctness of inference result (this is now handled by a deferred soundness checks) ! src/share/classes/com/sun/tools/javac/code/Printer.java ! src/share/classes/com/sun/tools/javac/code/Source.java ! src/share/classes/com/sun/tools/javac/code/Type.java ! src/share/classes/com/sun/tools/javac/code/TypeTags.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/AttrContext.java ! src/share/classes/com/sun/tools/javac/comp/Check.java + src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java ! src/share/classes/com/sun/tools/javac/comp/Infer.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/resources/compiler.properties ! src/share/classes/com/sun/tools/javac/tree/Pretty.java ! src/share/classes/com/sun/tools/javac/tree/TreeInfo.java ! src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java ! src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java ! test/tools/javac/6758789/T6758789b.out ! test/tools/javac/6840059/T6840059.out ! test/tools/javac/6979683/TestCast6979683_BAD34.java.errlog ! test/tools/javac/6979683/TestCast6979683_BAD35.java.errlog ! test/tools/javac/6979683/TestCast6979683_BAD36.java.errlog ! test/tools/javac/6979683/TestCast6979683_BAD37.java.errlog ! test/tools/javac/6979683/TestCast6979683_BAD38.java.errlog ! test/tools/javac/6979683/TestCast6979683_BAD39.java.errlog ! test/tools/javac/7132880/T7132880.out ! test/tools/javac/Diagnostics/6722234/T6722234a_1.out ! test/tools/javac/Diagnostics/6722234/T6722234a_2.out ! test/tools/javac/Diagnostics/6722234/T6722234b_1.out ! test/tools/javac/Diagnostics/6722234/T6722234b_2.out ! test/tools/javac/Diagnostics/6722234/T6722234c.out ! test/tools/javac/Diagnostics/6722234/T6722234d_1.out ! test/tools/javac/Diagnostics/6722234/T6722234d_2.out ! test/tools/javac/Diagnostics/6799605/T6799605.out ! test/tools/javac/Diagnostics/6862608/T6862608a.out ! test/tools/javac/Diagnostics/6862608/T6862608b.out ! test/tools/javac/OverrideChecks/6400189/T6400189a.out ! test/tools/javac/OverrideChecks/6400189/T6400189b.out ! test/tools/javac/StringsInSwitch/BadlyTypedLabel1.out ! test/tools/javac/StringsInSwitch/BadlyTypedLabel2.out ! test/tools/javac/T6326754.out ! test/tools/javac/TryWithResources/TwrOnNonResource.out ! test/tools/javac/cast/6270087/T6270087neg.out ! test/tools/javac/cast/6557182/T6557182.out ! test/tools/javac/cast/6665356/T6665356.out ! test/tools/javac/cast/6795580/T6795580.out ! test/tools/javac/cast/6932571/T6932571neg.out ! test/tools/javac/cast/7005095/T7005095neg.out ! test/tools/javac/cast/7005671/T7005671.out ! test/tools/javac/diags/examples.not-yet.txt ! test/tools/javac/diags/examples/ApplicableMethodFound1.java ! test/tools/javac/diags/examples/CantApplyDiamond1.java - test/tools/javac/diags/examples/FullInstSig.java ! test/tools/javac/diags/examples/IncompatibleTypes1.java ! test/tools/javac/diags/examples/InconvertibleTypes.java ! test/tools/javac/diags/examples/InferVarargsArgumentMismatch.java ! test/tools/javac/diags/examples/InferredDoNotConformToBounds.java - test/tools/javac/diags/examples/InvalidInferredTypes.java ! test/tools/javac/diags/examples/KindnameConstructor.java ! test/tools/javac/diags/examples/NotApplicableMethodFound.java ! test/tools/javac/diags/examples/PossibleLossPrecision.java ! test/tools/javac/diags/examples/ResourceNotApplicableToType.java ! test/tools/javac/diags/examples/UndeterminedType1.java ! test/tools/javac/diags/examples/VarargsArgumentMismatch.java ! test/tools/javac/diags/examples/VerboseResolveMulti1.java ! test/tools/javac/diags/examples/WhereCaptured.java ! test/tools/javac/diags/examples/WhereCaptured1.java ! test/tools/javac/diags/examples/WhereIntersection.java ! test/tools/javac/diags/examples/WhereTypeVar.java ! test/tools/javac/failover/CheckAttributedTree.java ! test/tools/javac/generics/6207386/T6207386.out ! test/tools/javac/generics/7015430/T7015430.out ! test/tools/javac/generics/7151802/T7151802.out ! test/tools/javac/generics/diamond/neg/Neg05.out ! test/tools/javac/generics/diamond/neg/Neg06.out ! test/tools/javac/generics/diamond/neg/Neg07.out ! test/tools/javac/generics/diamond/neg/Neg10.out ! test/tools/javac/generics/inference/6315770/T6315770.out ! test/tools/javac/generics/inference/6611449/T6611449.out ! test/tools/javac/generics/inference/6638712/T6638712a.out ! test/tools/javac/generics/inference/6638712/T6638712b.out ! test/tools/javac/generics/inference/6638712/T6638712c.out ! test/tools/javac/generics/inference/6638712/T6638712d.out ! test/tools/javac/generics/inference/6638712/T6638712e.out ! test/tools/javac/generics/inference/6650759/T6650759m.out ! test/tools/javac/generics/inference/6838943/T6838943.out ! test/tools/javac/generics/inference/7086586/T7086586.out ! test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java ! test/tools/javac/generics/rawOverride/7062745/T7062745neg.out ! test/tools/javac/generics/wildcards/6886247/T6886247_2.out ! test/tools/javac/lambda/BadConv03.out ! test/tools/javac/lambda/BadConv04.out ! test/tools/javac/lambda/BadExpressionLambda.out ! test/tools/javac/lambda/BadLambdaPos.out ! test/tools/javac/lambda/BadReturn.out ! test/tools/javac/lambda/BadTargetType.out ! test/tools/javac/lambda/LambdaConv09.out ! test/tools/javac/lambda/LambdaConv10.out ! test/tools/javac/lambda/LambdaConv21.out ! test/tools/javac/lambda/LambdaExpr10.out ! test/tools/javac/lambda/LambdaExprNotVoid.out ! test/tools/javac/lambda/MethodReference04.out ! test/tools/javac/lambda/MethodReference09.out ! test/tools/javac/lambda/MethodReference20.out ! test/tools/javac/lambda/MethodReference22.out ! test/tools/javac/lambda/MethodReference23.out ! test/tools/javac/lambda/MethodReference28.out ! test/tools/javac/lambda/TargetType04.out ! test/tools/javac/lambda/TargetType14.out ! test/tools/javac/lambda/TargetType17.out ! test/tools/javac/lambda/TargetType20.java + test/tools/javac/lambda/TargetType20.out ! test/tools/javac/lambda/TargetType21.out ! test/tools/javac/lambda/TargetType24.out ! test/tools/javac/lambda/TargetType27.java ! test/tools/javac/lambda/TargetType27.out ! test/tools/javac/lambda/TargetType28.out ! test/tools/javac/lambda/TargetType32.java - test/tools/javac/lambda/TargetType32.out ! test/tools/javac/lambda/TargetType33.out ! test/tools/javac/lambda/VoidCompatibility.out ! test/tools/javac/lambda/sqe/SAM_types/LambdaTest2_neg1.out ! test/tools/javac/lambda/sqe/SAM_types/NonSAM1.out ! test/tools/javac/lambda/sqe/SAM_types/NonSAM3.out ! test/tools/javac/lambda/sqe/lambdaExpression/AbstractClass_neg.out ! test/tools/javac/lambda/sqe/lambdaExpression/InvalidExpression3.out ! test/tools/javac/lambda/sqe/lambdaExpression/InvalidExpression4.out ! test/tools/javac/lambda/sqe/lambdaExpression/InvalidExpression5.out ! test/tools/javac/lambda/sqe/methodReference/MethodRef_neg.out ! test/tools/javac/multicatch/Neg06.out ! test/tools/javac/multicatch/Neg07.out ! test/tools/javac/nativeHeaders/NativeHeaderTest.java ! test/tools/javac/types/CastObjectToPrimitiveTest.out ! test/tools/javac/varargs/6313164/T6313164.out ! test/tools/javac/varargs/7097436/T7097436.out From maurizio.cimadamore at oracle.com Thu May 24 06:42:03 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Thu, 24 May 2012 13:42:03 +0000 Subject: hg: lambda/lambda/jdk: Lambda attribution overhaul. Message-ID: <20120524134233.2430E474C4@hg.openjdk.java.net> Changeset: 7152aca9aef1 Author: mcimadamore Date: 2012-05-24 14:41 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/7152aca9aef1 Lambda attribution overhaul. *) Modified src/share/classes/sun/awt/datatransfer/DataTransferer.java because of changes in conditional expression typing *) Added several combo tests to check new compiler features + combo-tests/tests/tools/javac/combo/StackProcessingUtils.java + combo-tests/tests/tools/javac/lambda/ConditionalExpressionTest.java + combo-tests/tests/tools/javac/lambda/LambdaExpressionTypeInferenceTest.java + combo-tests/tests/tools/javac/lambda/NestedGenericMethodCallTest.java ! src/share/classes/sun/awt/datatransfer/DataTransferer.java From maurizio.cimadamore at oracle.com Thu May 24 08:43:55 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 24 May 2012 16:43:55 +0100 Subject: lambda compiler implementation - third milestone Message-ID: <4FBE573B.5090304@oracle.com> Dear lambditizens, in the last few months I've been busy updating the javac infrastructure in the JDK 8 repo [1..10] and then rewrote (after a couple of painful merge rounds ;-)) the type-checking support for lambda/method reference from scratch, leveraging such architectural changes. This resulted in a much more cohesive implementation [11], that closely reflects the direction the language appears to be headed in (see below). There are, of course, few holes and gaps here and there, but, with your help, we'll work towards chasing'em all. One of the most important features supported in this new implementation is the long-awaited generalized support for target-typing in method context - this means that if you call a generic method or pass a diamond in a method context, javac will try its best in order to figure out what the inferred types are. Not all situations are handled, but the obvious ones should work as expected. As this is a big revolution in the way in which javac type-checks method calls, there could be some initial hiccups - in order to reduce the chance of regression as much as possible we also put in place a biggie suite of combinatorial test cases [12] - but please, be patient as new bugs might be uncovered. I would like to thank the many of you who provided very valuable feedback and bug reports - please keep it going! Maurizio [1] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/51fb17abfc32 [2] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/e28a06a3c5d9 [3] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/568e70bbd9aa [4] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/161230ec7c73 [5] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/6f0ed5a89c25 [6] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/2827076dbf64 [7] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/38ae13dcd215 [8] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/48ee63caaa93 [9] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/d2508136751c [10] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/dda6a5b15580 [11] - http://hg.openjdk.java.net/lambda/lambda/langtools/rev/314e550e28af [12] - http://hg.openjdk.java.net/lambda/lambda/jdk/rev/7152aca9aef1 From drconrad at gmail.com Thu May 24 12:37:48 2012 From: drconrad at gmail.com (David Conrad) Date: Thu, 24 May 2012 15:37:48 -0400 Subject: Compilation yields no class files, no errors In-Reply-To: <4FBE0EEA.8080702@oracle.com> References: <4FBE0EEA.8080702@oracle.com> Message-ID: Working now. Grazie. :) On Thu, May 24, 2012 at 6:35 AM, Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Fixed in the lambda repository. > Thanks for the report > > Maurizio > > From robert.field at oracle.com Thu May 24 21:08:07 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Fri, 25 May 2012 04:08:07 +0000 Subject: hg: lambda/lambda/langtools: Implement varg-args bridges into class-files for invokedynamic implementation. Derived from previous compiler bridging code. Message-ID: <20120525040811.4CAF9474FF@hg.openjdk.java.net> Changeset: 6f690e06d45d Author: Robert Field Date: 2012-05-24 20:14 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/6f690e06d45d Implement varg-args bridges into class-files for invokedynamic implementation. Derived from previous compiler bridging code. ! src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java From mcnepp02 at googlemail.com Fri May 25 05:10:00 2012 From: mcnepp02 at googlemail.com (Gernot Neppert) Date: Fri, 25 May 2012 14:10:00 +0200 Subject: Proposal: add unmodifiable() to Collection interface Message-ID: Hello, now that the Collections API is being revised with the help of 'Defender methods', I'd like to suggest adding the following method: interface Collection { ... /** Yields an unmodifiable view of this Collection. @return an unmodifiable view of this Collection. Can be {@code this} instance if it is already unmodifiable. */ Collection unmodifiable(); } For the rationale behind this proposal, consider the following, quite common example: public class Company { private final List customers; public Company(List customers) { this.customers = new ArrayList(customers); } public Company(List customers) { this.customers = Collections.emptyList(); } public List getCustomers() { return Collections.unmodifiableList(customers); } } As you can see, the method getCustomer() yields an unmodifiable view of the internal List, gratuitously creating a new instance even for empty Lists! The following package-private JDK classes could have overridden versions of the "unmodifiable" method that simply return "this": - java.util.Collections.UnmodifiableCollection - java.util.Collections.EmptySet - java.util.Collections.EmptyList - java.util.Collections.SingletonList - java.util.Collections.SingletonSet From keith.mcguigan at oracle.com Fri May 25 05:14:44 2012 From: keith.mcguigan at oracle.com (keith.mcguigan at oracle.com) Date: Fri, 25 May 2012 12:14:44 +0000 Subject: hg: lambda/lambda/hotspot: Summary: Update the original method order array when adding overpasses Message-ID: <20120525121448.184DF4750F@hg.openjdk.java.net> Changeset: 7757f2ffc48e Author: kamg Date: 2012-05-24 15:24 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/7757f2ffc48e Summary: Update the original method order array when adding overpasses ! src/share/vm/classfile/defaultMethods.cpp From keith.mcguigan at oracle.com Fri May 25 06:18:21 2012 From: keith.mcguigan at oracle.com (Keith McGuigan) Date: Fri, 25 May 2012 09:18:21 -0400 Subject: hg: lambda/lambda/hotspot: Summary: Update the original method order array when adding overpasses In-Reply-To: <20120525121448.184DF4750F@hg.openjdk.java.net> References: <20120525121448.184DF4750F@hg.openjdk.java.net> Message-ID: <4FBF869D.3010306@oracle.com> This should clear up some of the problems (i.e., crashes) that people have had when debugging extension methods. -- - Keith On 5/25/2012 8:14 AM, keith.mcguigan at oracle.com wrote: > Changeset: 7757f2ffc48e > Author: kamg > Date: 2012-05-24 15:24 -0400 > URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/7757f2ffc48e > > Summary: Update the original method order array when adding overpasses > > ! src/share/vm/classfile/defaultMethods.cpp > > From robert.field at oracle.com Fri May 25 19:55:42 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Sat, 26 May 2012 02:55:42 +0000 Subject: hg: lambda/lambda/jdk: Add method reference instance tests. Organize method reference tests separately. Message-ID: <20120526025609.19AAF47542@hg.openjdk.java.net> Changeset: 73cc90cf57b7 Author: Robert Field Date: 2012-05-25 19:52 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/73cc90cf57b7 Add method reference instance tests. Organize method reference tests separately. - test-ng/tests/org/openjdk/tests/javac/LambdaTranslationTestVarArgs.java + test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestInstance.java + test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestVarArgs.java From robert.field at oracle.com Fri May 25 19:58:28 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Sat, 26 May 2012 02:58:28 +0000 Subject: hg: lambda/lambda/langtools: Fix instance method reference implementation. Code clean-up. Message-ID: <20120526025835.A921347544@hg.openjdk.java.net> Changeset: 6bf46f31df7e Author: Robert Field Date: 2012-05-25 19:54 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/6bf46f31df7e Fix instance method reference implementation. Code clean-up. ! src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java From pbenedict at apache.org Fri May 25 20:03:42 2012 From: pbenedict at apache.org (Paul Benedict) Date: Fri, 25 May 2012 22:03:42 -0500 Subject: Method reference double-colon syntax Message-ID: Can anyone answer why the double-colon syntax was chosen for method references? I wonder if it was adopted from another language and what the expert group reasoned? Way back yonder, # was the initial proposal -- just curious what happened. Thanks! Paul From robert.field at oracle.com Fri May 25 21:04:35 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Sat, 26 May 2012 04:04:35 +0000 Subject: hg: lambda/lambda/langtools: Handle constructor method references. Message-ID: <20120526040437.C5B9547546@hg.openjdk.java.net> Changeset: 7aaa2d035ac1 Author: Robert Field Date: 2012-05-25 21:04 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/7aaa2d035ac1 Handle constructor method references. ! src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java From matthew at matthewadams.me Sat May 26 05:52:44 2012 From: matthew at matthewadams.me (Matthew Adams) Date: Sat, 26 May 2012 07:52:44 -0500 Subject: Method reference double-colon syntax In-Reply-To: References: Message-ID: Yeah, I liked the # syntax proposal better, too. One less character to type! :) On Fri, May 25, 2012 at 10:03 PM, Paul Benedict wrote: > Can anyone answer why the double-colon syntax was chosen for method > references? I wonder if it was adopted from another language and what > the expert group reasoned? Way back yonder, # was the initial proposal > -- just curious what happened. > > Thanks! > Paul > -- @matthewadams12 mailto:matthew at matthewadams.me skype:matthewadams12 yahoo:matthewadams aol:matthewadams12 google-talk:matthewadams12 at gmail.com msn:matthew at matthewadams.me http://matthewadams.me http://www.linkedin.com/in/matthewadams From martijnverburg at gmail.com Sat May 26 06:02:13 2012 From: martijnverburg at gmail.com (Martijn Verburg) Date: Sat, 26 May 2012 14:02:13 +0100 Subject: Method reference double-colon syntax In-Reply-To: References: Message-ID: I'm pretty sure this is covered in the mailing list archives - M On 26 May 2012 13:52, Matthew Adams wrote: > Yeah, I liked the # syntax proposal better, too. ?One less character > to type! ?:) > > On Fri, May 25, 2012 at 10:03 PM, Paul Benedict wrote: >> Can anyone answer why the double-colon syntax was chosen for method >> references? I wonder if it was adopted from another language and what >> the expert group reasoned? Way back yonder, # was the initial proposal >> -- just curious what happened. >> >> Thanks! >> Paul >> > > > > -- > @matthewadams12 > mailto:matthew at matthewadams.me > skype:matthewadams12 > yahoo:matthewadams > aol:matthewadams12 > google-talk:matthewadams12 at gmail.com > msn:matthew at matthewadams.me > http://matthewadams.me > http://www.linkedin.com/in/matthewadams > From peter.levart at gmail.com Sun May 27 02:03:28 2012 From: peter.levart at gmail.com (Peter Levart) Date: Sun, 27 May 2012 11:03:28 +0200 Subject: lambda compiler implementation - third milestone In-Reply-To: <4FBE573B.5090304@oracle.com> References: <4FBE573B.5090304@oracle.com> Message-ID: <9359206.NkBhOxEizL@cube> On Thursday, May 24, 2012 04:43:55 PM Maurizio Cimadamore wrote: > Dear lambditizens, Hello Maurizio, I have just built the newest lambda jdk and am trying it out. > in the last few months I've been busy updating the javac infrastructure > in the JDK 8 repo [1..10] and then rewrote (after a couple of painful > merge rounds ;-)) the type-checking support for lambda/method reference > from scratch, leveraging such architectural changes. This resulted in a > much more cohesive implementation [11], that closely reflects the > direction the language appears to be headed in (see below). There are, > of course, few holes and gaps here and there, but, with your help, we'll > work towards chasing'em all. > > One of the most important features supported in this new implementation > is the long-awaited generalized support for target-typing in method > context - this means that if you call a generic method or pass a diamond > in a method context, javac will try its best in order to figure out what > the inferred types are. Not all situations are handled, but the obvious > ones should work as expected. // I have tried 2 basic use cases that someone might naively expect to work: public class InferTest { public > C test0() { return null; } public > C test1(C collection) { return collection; } public > C test2() { return null; } public > C test3(C collection) { return collection; } public static void main(String[] args) { InferTest stringTest = new InferTest<>(); // case 1: List strings0 = stringTest.test0(); List strings1a = stringTest.test1(new ArrayList<>()); List strings1b = stringTest.>test1(new ArrayList<>()); List strings1c = stringTest.test1(new ArrayList()); // case 2: List strings2 = stringTest.test2(); List strings3a = stringTest.test3(new ArrayList<>()); List strings3b = stringTest.>test3(new ArrayList<>()); List strings3c = stringTest.test3(new ArrayList()); } } ... The strings0 assignment infers the C of test0() as something that can be assigned to List, so one might expect that such inferred type could be used to infer types in method argument context (left to right), but... The strings1a assignment fails with: error: method test1 in class InferTest cannot be applied to given types; required: C found: ArrayList reason: inferred type does not conform to declared bound(s) inferred: ArrayList bound(s): Collection where C,T are type-variables: C extends Collection declared in method test1(C) T extends Object declared in class InferTest So one must either use strings1b or strings1c to make it work. The other use-case is using a wild-card with "? super T" bound on a nested type parameter. The strings2 assignment infers C of test2() as something assignable to List, but... The strings3a assignment fails with: error: incompatible types: ArrayList cannot be converted to List So one must use either strings3b or strings3c. Is any of the two use-cases expected to work in the new scheme? Regards, Peter > > As this is a big revolution in the way in which javac type-checks method > calls, there could be some initial hiccups - in order to reduce the > chance of regression as much as possible we also put in place a biggie > suite of combinatorial test cases [12] - but please, be patient as new > bugs might be uncovered. > > I would like to thank the many of you who provided very valuable > feedback and bug reports - please keep it going! > > Maurizio > > [1] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/51fb17abfc32 > [2] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/e28a06a3c5d9 > [3] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/568e70bbd9aa > [4] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/161230ec7c73 > [5] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/6f0ed5a89c25 > [6] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/2827076dbf64 > [7] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/38ae13dcd215 > [8] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/48ee63caaa93 > [9] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/d2508136751c > [10] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/dda6a5b15580 > [11] - http://hg.openjdk.java.net/lambda/lambda/langtools/rev/314e550e28af > [12] - http://hg.openjdk.java.net/lambda/lambda/jdk/rev/7152aca9aef1 From maurizio.cimadamore at oracle.com Sun May 27 04:03:41 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Sun, 27 May 2012 12:03:41 +0100 Subject: lambda compiler implementation - third milestone In-Reply-To: <9359206.NkBhOxEizL@cube> References: <4FBE573B.5090304@oracle.com> <9359206.NkBhOxEizL@cube> Message-ID: <4FC20A0D.5040707@oracle.com> On 27/05/12 10:03, Peter Levart wrote: > On Thursday, May 24, 2012 04:43:55 PM Maurizio Cimadamore wrote: >> Dear lambditizens, > Hello Maurizio, > > I have just built the newest lambda jdk and am trying it out. > >> in the last few months I've been busy updating the javac infrastructure >> in the JDK 8 repo [1..10] and then rewrote (after a couple of painful >> merge rounds ;-)) the type-checking support for lambda/method reference >> from scratch, leveraging such architectural changes. This resulted in a >> much more cohesive implementation [11], that closely reflects the >> direction the language appears to be headed in (see below). There are, >> of course, few holes and gaps here and there, but, with your help, we'll >> work towards chasing'em all. >> >> One of the most important features supported in this new implementation >> is the long-awaited generalized support for target-typing in method >> context - this means that if you call a generic method or pass a diamond >> in a method context, javac will try its best in order to figure out what >> the inferred types are. Not all situations are handled, but the obvious >> ones should work as expected. The examples you listed are not supported. My idea of naive is: m(List ls) { ... } m(new ArrayList<>) If you have inference variables on both ends, you have an inference cycle. Now, since Java overload resolution is a function of argument types only (the target type of the assignment is only considered at a later stage), we are not supposed to look into that during overload resolution. It's also a problem of whether we want inference to be more global vs. keeping it local - your case might look reasonable enough - but then what about: List ls = m(m(m(m(ArrayList<>)))); Making inference more powerful will make those problems disappear, that will have other side-effects - for instance the fact that you will get strange error messages in unexpected places (as the compiler 'delays' the time at which inference is performed to wait for some constraints). All these design dimensions are on the table as we speak - for now the compiler leaves cyclic inferences cases alone, and treats them in a backward compatible fashion. Maurizio > // I have tried 2 basic use cases that someone might naively expect to work: > > public class InferTest > { > public> C test0() > { > return null; > } > > public> C test1(C collection) > { > return collection; > } > > public> C test2() > { > return null; > } > > public> C test3(C collection) > { > return collection; > } > > public static void main(String[] args) > { > InferTest stringTest = new InferTest<>(); > > // case 1: > > List strings0 = stringTest.test0(); > > List strings1a = stringTest.test1(new ArrayList<>()); > List strings1b = stringTest.>test1(new ArrayList<>()); > List strings1c = stringTest.test1(new ArrayList()); > > // case 2: > > List strings2 = stringTest.test2(); > > List strings3a = stringTest.test3(new ArrayList<>()); > List strings3b = stringTest.>test3(new ArrayList<>()); > List strings3c = stringTest.test3(new ArrayList()); > } > } > > > ... > > The strings0 assignment infers the C oftest0() as something that can be assigned to List, so one might expect that such inferred type could be used to infer types in method argument context (left to right), but... > > The strings1a assignment fails with: > > error: method test1 in class InferTest cannot be applied to given types; > required: C > found: ArrayList > reason: inferred type does not conform to declared bound(s) > inferred: ArrayList > bound(s): Collection > where C,T are type-variables: > C extends Collection declared in methodtest1(C) > T extends Object declared in class InferTest > > So one must either use strings1b or strings1c to make it work. > > > The other use-case is using a wild-card with "? super T" bound on a nested type parameter. The strings2 assignment infers C oftest2() as something assignable to List, but... > > The strings3a assignment fails with: > > error: incompatible types: ArrayList cannot be converted to List > > So one must use either strings3b or strings3c. > > > Is any of the two use-cases expected to work in the new scheme? > > Regards, Peter > >> As this is a big revolution in the way in which javac type-checks method >> calls, there could be some initial hiccups - in order to reduce the >> chance of regression as much as possible we also put in place a biggie >> suite of combinatorial test cases [12] - but please, be patient as new >> bugs might be uncovered. >> >> I would like to thank the many of you who provided very valuable >> feedback and bug reports - please keep it going! >> >> Maurizio >> >> [1] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/51fb17abfc32 >> [2] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/e28a06a3c5d9 >> [3] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/568e70bbd9aa >> [4] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/161230ec7c73 >> [5] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/6f0ed5a89c25 >> [6] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/2827076dbf64 >> [7] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/38ae13dcd215 >> [8] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/48ee63caaa93 >> [9] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/d2508136751c >> [10] - http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/dda6a5b15580 >> [11] - http://hg.openjdk.java.net/lambda/lambda/langtools/rev/314e550e28af >> [12] - http://hg.openjdk.java.net/lambda/lambda/jdk/rev/7152aca9aef1 From robert.field at oracle.com Mon May 28 16:23:05 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Mon, 28 May 2012 23:23:05 +0000 Subject: hg: lambda/lambda/jdk: Tests for var args via instance. Message-ID: <20120528232324.BC80347575@hg.openjdk.java.net> Changeset: cd848b0f97f7 Author: Robert Field Date: 2012-05-28 16:22 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/cd848b0f97f7 Tests for var args via instance. + test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestVarArgsExt.java + test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestVarArgsThis.java From robert.field at oracle.com Mon May 28 16:24:36 2012 From: robert.field at oracle.com (robert.field at oracle.com) Date: Mon, 28 May 2012 23:24:36 +0000 Subject: hg: lambda/lambda/langtools: Implement var-args on instance access. Message-ID: <20120528232438.D84A047576@hg.openjdk.java.net> Changeset: 10c9dc8899b5 Author: Robert Field Date: 2012-05-28 16:25 -0700 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/10c9dc8899b5 Implement var-args on instance access. ! src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java From maurizio.cimadamore at oracle.com Tue May 29 05:43:24 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Tue, 29 May 2012 12:43:24 +0000 Subject: hg: lambda/lambda/langtools: Implement more refined effectively-final analysis based on DA/DU rules Message-ID: <20120529124329.C154947590@hg.openjdk.java.net> Changeset: c9a2ed981af2 Author: mcimadamore Date: 2012-05-29 13:41 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/c9a2ed981af2 Implement more refined effectively-final analysis based on DA/DU rules Effectively final now supports blank locals - i.e. int i; if (cond) { i = 10; } else { i = 5; } SAM s = ()-> i * i; //ok - i is effectively final ! src/share/classes/com/sun/tools/javac/comp/Attr.java ! src/share/classes/com/sun/tools/javac/comp/Flow.java ! src/share/classes/com/sun/tools/javac/resources/compiler.properties ! test/tools/javac/diags/examples.not-yet.txt + test/tools/javac/lambda/EffectivelyFinalTest.java + test/tools/javac/lambda/EffectivelyFinalTest.out From richard.warburton at gmail.com Tue May 29 06:30:02 2012 From: richard.warburton at gmail.com (Richard Warburton) Date: Tue, 29 May 2012 16:30:02 +0300 Subject: LJC Lambdas Hackday Message-ID: On Sunday 27th May, the London Java Community ran a lambdas hackday as part of the Adopt OpenJDK program. We had a mixture of different abilities and experiences, a couple of people had written some Scala, Clojure or Haskell before, but most people were day-to-day Java developers without that background. We split people into groups of 3 or 4, gave them the lambdafied Java 8 build (thanks Brian & team!) and a little bit of understanding to begin with. They then wrote a few simple Collections based programs in the morning, and tried to lambda-ise parts of the Cassandra Database in the afternoon. Here?s a summary of what we learnt. Bugs 1. Target typing for diamond operators being passed into methods doesn?t seem to work quite right at the moment. This compiles ok: public static void main(String[] args) { List appended = Arrays.asList(args) .map(x -> x + "suffix") .into(new ArrayList()); System.out.println(appended); } If we compile: public static void main(String[] args) { List appended = Arrays.asList(args) .map(x -> x + "suffix") .into(new ArrayList<>()); System.out.println(appended); } Then we get a compile error: Foo.java:8: error: incompatible types .into(new ArrayList<>()); ^ required: List found: ArrayList 1 error 2. The state of the lambda collections libraries document lists several methods that haven?t been implemented yet, for example sum() and mapBy(). On a side note - sum() seems like an interesting method, what is its type? There?s another bug around generics that Ben will be emailing through, when he has a extracted a minimal testcase. Common Mistakes Several different people made similar mistakes when trying to write simple lambda based Java 8 code. I don?t think these are necessarily design weaknesses, but they are things that need to be thought through in terms of how you educate people about lambdas and how you promote lambdas. 1. People thinking that map/reduce return an eagerly evaluated List, rather than a lazily evaluated Iterable. This was especially confusing when we discussed the sorted method, and whether calling getFirst() on a lazy iterator ends up generating any iterators that you?ve dependently chained. A brief scan of the source shows you?re using a priority queue, but this is the kind of thing that people will get confused at when you?re now talking about a lot of their collections operations being lazy. I don?t think anyone disagreed with the core idea that you chain a sequence of lazy operations, and then had an eager evaluation at the end. At least no one had a compelling use case that this didn?t work with. I think it will take time for people to become used to and comfortable with this idea. 2. Some programmers appear to have basically no functional programming experience and were confused as to why they couldn?t assign back to their parameter in a map. For example they wanted to write: someIntegers.forEach(x -> x = x + 1) rather than: someIntegers.map(x -> x + 1) I know this might sound silly to people subscribed to lambda-dev, but getting people out of a solely imperative mindset of one of the adoption challenges that is faced by this JSR. If I may be so bold as to make a suggestion in order to help people in the right direction: lambda arguments being default final. (Or maybe even always final) 3. Expressions that evaluate to void vs code blocks. ?someStrings.forEach(s -> System.out.println(s));? doesn?t compile because the function call is an expression that evaluates to void, so it's incompatible with Block. ?someStrings.forEach(s -> { System.out.println(s); });? works fine because the braces with no return allow the user to convince javac that it's returning a void. Two different groups of 4 people and at least one of the instructors found this quite confusing. In many functional languages, with the equivalent of void (Unit, etc) being a normal type, the first statement would have type checked. Opinions These are opinions that I sourced from people whilst they were using the lambdas build. All of them were supported by at least 2 people and many of them were common threads when talking to different groups of programmers. 1. Javadoc needs examples. For a lot of Java developers they?ll have a problem and need to figure out which higher order function is appropriate for their use case. For example they have a list of numbers that they wish to increment, but they?ll need to figure out whether they want to use map or reduce. Again - seems trivial to people with some experience but many won?t have that experience. In this case the style of Javadoc - ie explain what?s happening - that?s throughout Collections isn?t necessarily that appropriate. It would be much more helpful to have a simple code example in order for people to grok the pattern that they need to apply. E.g. Incrementing numbers for map, concatenating a list of strings for reduce etc. It would also help people coming from other backgrounds if methods listed similar method names. For example you could say that the method ?reduce? might be called ?fold? in other languages. I appreciate this isn?t /technically/ correct - but it helps people build an intuitive understanding of what?s going on here and helps get them up to speed quickly. Just don?t say that they?re catamorphisms or people will try to google catamorphism and quickly become confused ;) 2. Complex types are hard to read and understand. Scala already gets a really bad rep for this, and Java will as well if you?re not careful. Consider the function map?s signature: public static Iterable map(final Iterable iterable, final Mapper mapper) There are a couple of things that you can do on a practical level to help people understand this better. a. Write Javadoc in a way that discourages people from reading the types in order to figure out what?s going on. So, if the javadoc explains what a mapper is, and what the Iterable is that?s returned then you don?t need to understand the types at all. b. Use sensible type parameter names. The basic fact is that generic parameters are variables - they simply range over sets of types, rather than sets of values - so why not apply descriptive rules for variable names as you would normal variables. For example: public static Iterable map(final Iterable iterable, final Mapper mapper) Now you don?t get people looking at the type signature and immediately asking themselves - what does ?U? mean? 3. Since other type quantifiers like final and public are on the left hand side of a method, perhaps default should go there as well? I?m not really a big fan of syntax discussion in general, but this was the one syntactic point that was brought up that I don?t think was discussed here previously. 4. When trying to lambda-ise cassandra it became clear that frequently you have a list that has multiple responsibilities. If you were to lambda-ise it, then you?d split things out into multiple calls and chain them together. This means that in many cases there will be some refactoring needed in order to introduce lambda usage. Some people commented that in their workplace the risk of changing reliably working code outweighs the potential benefits that you?re providing. Perhaps there?s no good way to address this issue - I certainly have no suggestions other than getting people to write clean code with high test coverage so they can easily refactor. 5. Some anonymous inner classes ended up with a hell of a lot of parameters (e.g. 7) being passed in. In this case people seemed to prefer to continue using anonymous inner classes, rather than splitting up the parameter declaration of a lambda expression over several lines. Future Directions When trying to lambda-ise cassandra we ran into several Apache Ant bugs that we established temporary workarounds for. I think before we run an event like this again we?ll want to patch Ant so that it works ok. Do you guys have internal builds of ant that work ok with Java 8? If you don?t, I?m sure we?re more than capable of fixing the problem, but its still easier if we don?t have to! regards, Richard, Ben and Martijn From maurizio.cimadamore at oracle.com Tue May 29 06:35:16 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 29 May 2012 14:35:16 +0100 Subject: LJC Lambdas Hackday In-Reply-To: References: Message-ID: <4FC4D094.2010102@oracle.com> On 29/05/12 14:30, Richard Warburton wrote: > 1. Target typing for diamond operators being passed into methods > doesn?t seem to work quite right at the moment. This compiles ok: Thanks for the feedback - the rationale for the current compiler behaviour is explained in more details here: http://mail.openjdk.java.net/pipermail/lambda-dev/2012-May/004951.html Maurizio From brian.goetz at oracle.com Tue May 29 07:11:18 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 May 2012 10:11:18 -0400 Subject: LJC Lambdas Hackday In-Reply-To: References: Message-ID: <4FC4D906.6080304@oracle.com> Thanks for the effort and the writeup! This has been extremely helpful for us! Some comments: > Bugs > > 1. Target typing for diamond operators being passed into methods > doesn?t seem to work quite right at the moment. I wish we could consider this a simple bug, but as Maurizio points out, this is a pretty big leap from local type inference towards more global type inference. We're evaluating our options here, but if we could have fixed this already, we would have :( > 2. The state of the lambda collections libraries document lists > several methods that haven?t been implemented yet, for example sum() > and mapBy(). On a side note - sum() seems like an interesting method, > what is its type? And now you've discovered the reason why it is not yet implemented :) Our story for primitives is still being mapped out, and there are a number of options here. If we choose to go in the direction of specializing streams for the common primitives (Int/Long/DoubleStream), then the sum() method would live there and its type would be obvious. Another alternative is to fuse mapping and reducing into a single operations, and have a sumBy(IntMapper) operation. > 1. People thinking that map/reduce return an eagerly evaluated List, > rather than a lazily evaluated Iterable. This was especially confusing > when we discussed the sorted method, and whether calling getFirst() on > a lazy iterator ends up generating any iterators that you?ve > dependently chained. A brief scan of the source shows you?re using a > priority queue, but this is the kind of thing that people will get > confused at when you?re now talking about a lot of their collections > operations being lazy. Yes, this is one of the key education points we need to address. Laziness can be surprising, and the sorted() method is among the weirdest (it is lazy in the sense that no computation happens when you call sorted(), but eager in the sense that much or all of computation has already happened by the time the first element comes out.) We've come to the conclusion that putting these methods on Iterable makes the confusion surrounding laziness worse, given that most Iterables (though not all) are backed by data structures and this colors our thinking. Instead, the Stream abstraction should behave more like an Iterator, and I think this will help a lot -- if filter returns a Stream, the idea that it will be lazily computed comes more readily to mind. > 2. Some programmers appear to have basically no functional programming > experience and were confused as to why they couldn?t assign back to > their parameter in a map. For example they wanted to write: > > someIntegers.forEach(x -> x = x + 1) > > rather than: > > someIntegers.map(x -> x + 1) > > I know this might sound silly to people subscribed to lambda-dev, but > getting people out of a solely imperative mindset of one of the > adoption challenges that is faced by this JSR. If I may be so bold as > to make a suggestion in order to help people in the right direction: > lambda arguments being default final. (Or maybe even always final) This is worth considering. Sadly it would be an assymmetry with inner classes (we are extending the treatment of effectively final to inner classes, and generally trying to reduce gratuitous differences.) > 3. Expressions that evaluate to void vs code blocks. > > ?someStrings.forEach(s -> System.out.println(s));? > > doesn?t compile because the function call is an expression that > evaluates to void, so it's incompatible with Block. > > ?someStrings.forEach(s -> { System.out.println(s); });? > > works fine because the braces with no return allow the user to > convince javac that it's returning a void. > > Two different groups of 4 people and at least one of the instructors > found this quite confusing. In many functional languages, with the > equivalent of void (Unit, etc) being a normal type, the first > statement would have type checked. Yes, we've been worried about this as well. The nice division between expression lambdas and statement lambdas is clean, and that cleanliness makes it possible to make better decisions about things like overload selection. However, as you point out, it may well just be too rigid for most people's conception of what void means. We're experimenting with some alternatives. > Opinions > > These are opinions that I sourced from people whilst they were using > the lambdas build. All of them were supported by at least 2 people > and many of them were common threads when talking to different groups > of programmers. > > 1. Javadoc needs examples. For a lot of Java developers they?ll have > a problem and need to figure out which higher order function is > appropriate for their use case. For example they have a list of > numbers that they wish to increment, but they?ll need to figure out > whether they want to use map or reduce. Again - seems trivial to > people with some experience but many won?t have that experience. In > this case the style of Javadoc - ie explain what?s happening - that?s > throughout Collections isn?t necessarily that appropriate. It would > be much more helpful to have a simple code example in order for people > to grok the pattern that they need to apply. E.g. Incrementing > numbers for map, concatenating a list of strings for reduce etc. It > would also help people coming from other backgrounds if methods listed > similar method names. Absolutely. We made the deliberate choice to invest less in Javadoc while the API is in flux, to allow for more rapid turns, but I agree it is an impediment to understanding. > 2. Complex types are hard to read and understand. Scala already gets > a really bad rep for this, and Java will as well if you?re not > careful. Consider the function map?s signature: > > public static Iterable map(final Iterable > iterable, final Mapper mapper) > > There are a couple of things that you can do on a practical level to > help people understand this better. > > a. Write Javadoc in a way that discourages people from reading the > types in order to figure out what?s going on. So, if the javadoc > explains what a mapper is, and what the Iterable is that?s returned > then you don?t need to understand the types at all. > > b. Use sensible type parameter names. The basic fact is that generic > parameters are variables - they simply range over sets of types, > rather than sets of values - so why not apply descriptive rules for > variable names as you would normal variables. For example: > > public static Iterable map(final Iterable From> iterable, final Mapper mapper) > > Now you don?t get people looking at the type signature and immediately > asking themselves - what does ?U? mean? Agreed. I always felt that the "one letter rule" was borne of a delusion that type parameters would only be used in obvious ways, such as the elements of a collection. But we passed that long ago, and we should acknowledge it. The wildcards don't help either :( > When trying to lambda-ise cassandra we ran into several Apache Ant > bugs that we established temporary workarounds for. I think before we > run an event like this again we?ll want to patch Ant so that it works > ok. Do you guys have internal builds of ant that work ok with Java 8? > If you don?t, I?m sure we?re more than capable of fixing the problem, > but its still easier if we don?t have to! We haven't run into these issues. I use a relatively old version of ANT for running tests and haven't seen these yet. Thanks again! Great input. From richard.warburton at gmail.com Tue May 29 07:51:32 2012 From: richard.warburton at gmail.com (Richard Warburton) Date: Tue, 29 May 2012 15:51:32 +0100 Subject: LJC Lambdas Hackday In-Reply-To: <4FC4D906.6080304@oracle.com> References: <4FC4D906.6080304@oracle.com> Message-ID: > Thanks for the effort and the writeup! ?This has been extremely helpful for > us! Glad to help. > And now you've discovered the reason why it is not yet implemented :) Our > story for primitives is still being mapped out, and there are a number of > options here. ?If we choose to go in the direction of specializing streams > for the common primitives (Int/Long/DoubleStream), then the sum() method > would live there and its type would be obvious. Another alternative is to > fuse mapping and reducing into a single operations, and have a > sumBy(IntMapper) operation. I think it might well be useful to have sum operate over types generally. So if you have a Stream and can provide a Mapper then you can sumBy generally. Obviously there are a variety of mathematical structures that you might want to sum that aren't primitives - for example a vector. I'd probably expect that many domain objects are the kind of things that you want to sum over as well in some cases. Presumably any domain object that's a commutative monoid is safe for this kind of stuff? In these cases I think its safe for the signature of sumBy to be: T sumBy(Iterable values, Mapper summer) And people can provide their definition of the summer function, instead of explicitly restricting the type of to things that you can already syntactically do t1 + t2 on. > Yes, this is one of the key education points we need to address. Laziness > can be surprising, and the sorted() method is among the weirdest (it is lazy > in the sense that no computation happens when you call sorted(), but eager > in the sense that much or all of computation has already happened by the > time the first element comes out.) Yeah - I think that's the kind of thing that's absolutely fine - provided it says so in the Javadoc. I guess what I'm saying is that you want to avoid the situation that new haskell programmers sometimes find themselves in - when their brilliant 1 line fibonacci function has just finished calculating the 1 billionth fibonacci instantly, but they are stuck wondering it takes them hours to print that number out. > We've come to the conclusion that putting these methods on Iterable makes > the confusion surrounding laziness worse, given that most Iterables (though > not all) are backed by data structures and this colors our thinking. > ?Instead, the Stream abstraction should behave more like an Iterator, and I > think this will help a lot -- if filter returns a Stream, the idea that it > will be lazily computed comes more readily to mind. I think this makes a lot of sense, hopefully we can gauge its effect on how easy it is for people to understand things with another lambda hackday at some point. > Agreed. ?I always felt that the "one letter rule" was borne of a delusion > that type parameters would only be used in obvious ways, such as the > elements of a collection. ?But we passed that long ago, and we should > acknowledge it. Exactly. regards, Richard From benjamin.john.evans at gmail.com Tue May 29 08:07:09 2012 From: benjamin.john.evans at gmail.com (Ben Evans) Date: Tue, 29 May 2012 16:07:09 +0100 Subject: Generics oddness Message-ID: Hi, At Sunday's Lambdas Hackday, we discovered an issue with Apache Cassandra's use of Google Guava. Specifically, Guava defines an Ordering class which implements Comparator. Ordering defines reverse(), which is of course now present on Comparator, and causes javac to complain: This reduces to the following test case: public class Ordering implements Comparator { @Override public int compare(T o1, T o2) { // ... } public Ordering reverse() { // ... } } public class OrderingMain { Ordering myOrdering; public Ordering get() { return myOrdering.reverse(); } } This compiles fine under JDK 7. Under JDK 8 Ordering compiles fine. OrderingMain fails with this error: hackday1/OrderingMain.java:20: error: reference to reverse is ambiguous, both method reverse() in Comparator and method reverse() in Ordering match return myOrdering.reverse(); ^ where T#1,S,T#2 are type-variables: T#1 extends Object declared in interface Comparator S extends T#2 declared in method reverse() T#2 extends Object declared in class Ordering hackday1/OrderingMain.java:20: error: incompatible types return myOrdering.reverse(); ^ required: Ordering found: Comparator where T is a type-variable: T extends Object declared in class OrderingMain 2 errors I've stared at this extensively over the last couple of days, and come to the conclusion that I don't understand this behaviour. Is this a bug? If not, can someone untangle what's happening here for me? Thanks, Ben From brian.goetz at oracle.com Tue May 29 08:15:09 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 May 2012 11:15:09 -0400 Subject: LJC Lambdas Hackday In-Reply-To: References: <4FC4D906.6080304@oracle.com> Message-ID: <4FC4E7FD.9050705@oracle.com> > I think it might well be useful to have sum operate over types > generally. So if you have a Stream and can provide a Mapper > then you can sumBy generally. Obviously there are a variety of > mathematical structures that you might want to sum that aren't > primitives - for example a vector. I'd probably expect that many > domain objects are the kind of things that you want to sum over as > well in some cases. Presumably any domain object that's a commutative > monoid is safe for this kind of stuff? > > In these cases I think its safe for the signature of sumBy to be: > > T sumBy(Iterable values, Mapper summer) You can think of sumBy(IntMapper) as a simplified form of mapReduce(Mapper, BinaryOperator) in the cases where the sum operation is obvious for the type. (The primary benefit of a fused mapReduce over the components map+reduce is that if the mapper maps to primitives, then the boxing can be avoided.) Zooming out: I think the biggest adoption problem we face is: reduce. When confronted with reduce, devs are going to let out a big collective "WTF?" This is another reason why some variant of sum() is important -- it is the onramp to understanding reduce. Asking people to jump from imperative addition to reduce in one go is unrealistic. From brian.goetz at oracle.com Tue May 29 08:17:32 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 May 2012 11:17:32 -0400 Subject: Generics oddness In-Reply-To: References: Message-ID: <4FC4E88C.7070708@oracle.com> The number of generic type parameters is one of the many axes on which two methods are judged to be similar enough to be the same method. On 5/29/2012 11:07 AM, Ben Evans wrote: > Hi, > > At Sunday's Lambdas Hackday, we discovered an issue with Apache > Cassandra's use of Google Guava. > > Specifically, Guava defines an Ordering class which implements Comparator. > > Ordering defines reverse(), which is of course now present on > Comparator, and causes javac to complain: > > This reduces to the following test case: > > public class Ordering implements Comparator { > @Override > public int compare(T o1, T o2) { > // ... > } > > public Ordering reverse() { > // ... > } > } > > public class OrderingMain { > Ordering myOrdering; > > public Ordering get() { > return myOrdering.reverse(); > } > } > > This compiles fine under JDK 7. > > Under JDK 8 Ordering compiles fine. OrderingMain fails with this error: > > hackday1/OrderingMain.java:20: error: reference to reverse is > ambiguous, both method reverse() in Comparator and methodreverse() > in Ordering match > return myOrdering.reverse(); > ^ > where T#1,S,T#2 are type-variables: > T#1 extends Object declared in interface Comparator > S extends T#2 declared in methodreverse() > T#2 extends Object declared in class Ordering > hackday1/OrderingMain.java:20: error: incompatible types > return myOrdering.reverse(); > ^ > required: Ordering > found: Comparator > where T is a type-variable: > T extends Object declared in class OrderingMain > 2 errors > > I've stared at this extensively over the last couple of days, and come > to the conclusion that I don't understand this behaviour. > > Is this a bug? If not, can someone untangle what's happening here for me? > > Thanks, > > Ben > From maurizio.cimadamore at oracle.com Tue May 29 08:40:12 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 29 May 2012 16:40:12 +0100 Subject: Generics oddness In-Reply-To: References: Message-ID: <4FC4EDDC.8080603@oracle.com> Hi Ben, the problem is that there is a clash between two methods that are not-override equivalent; one is class Comparator { [...] Comparator reverse() default { return Collections.reverseOrder(this); } [...] } The other one is: class Ordering implements Comparator { public Ordering reverse() { // ... } } As per JLS, this is an illegal override, as Ordering.reverse is not a subsignature of Comparator.reverse (as the number of type parameter differs). However, I'm investigating as to why the compiler is not reporting a clash (as it should). Thanks Maurizio On 29/05/12 16:07, Ben Evans wrote: > public class Ordering implements Comparator { > @Override > public int compare(T o1, T o2) { > // ... > } > > public Ordering reverse() { > // ... > } > } > > public class OrderingMain { > Ordering myOrdering; > > public Ordering get() { > return myOrdering.reverse(); > } > } From zhong.j.yu at gmail.com Tue May 29 08:43:02 2012 From: zhong.j.yu at gmail.com (Zhong Yu) Date: Tue, 29 May 2012 10:43:02 -0500 Subject: LJC Lambdas Hackday In-Reply-To: References: Message-ID: > 2. Complex types are hard to read and understand. ?Scala already gets > a really bad rep for this, and Java will as well if you?re not > careful. ?Consider the function map?s signature: > > public static Iterable map(final Iterable > iterable, final Mapper mapper) The only problem I see in this example is the dreadful syntax of wildcard. The original syntax (Itreable<+T>, Mapper<-T,+U>) would be much better. "? extends/super" does the exact opposite of helping readability. Maybe it's just me, but every sight of "? extends/super" sends my brain to a micro stroke. And API users don't event want to read about variance; their code, written out of instinct without thinking of variance, simply compiles (thanks to API designers). Forcing API users to wade through "? extends" and "? super" to get to the type they care about (T,U) is unnecessary punishment. Zhong Yu From kevinb at google.com Tue May 29 08:44:56 2012 From: kevinb at google.com (Kevin Bourrillion) Date: Tue, 29 May 2012 08:44:56 -0700 Subject: Generics oddness In-Reply-To: <4FC4EDDC.8080603@oracle.com> References: <4FC4EDDC.8080603@oracle.com> Message-ID: You might need the parameter that Guava uses anyway -- before we had it, code like this would not compile: Comparator reverseInts = Ordering.natural().reverse(); On Tue, May 29, 2012 at 8:40 AM, Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Hi Ben, > the problem is that there is a clash between two methods that are > not-override equivalent; one is > > class Comparator { > [...] > Comparator reverse() default { > return Collections.reverseOrder(this); > } > [...] > } > > > The other one is: > > class Ordering implements Comparator { > public Ordering reverse() { > // ... > } > } > > As per JLS, this is an illegal override, as Ordering.reverse is not a > subsignature of Comparator.reverse (as the number of type parameter > differs). However, I'm investigating as to why the compiler is not > reporting a clash (as it should). > > Thanks > Maurizio > > On 29/05/12 16:07, Ben Evans wrote: > > public class Ordering implements Comparator { > > @Override > > public int compare(T o1, T o2) { > > // ... > > } > > > > public Ordering reverse() { > > // ... > > } > > } > > > > public class OrderingMain { > > Ordering myOrdering; > > > > public Ordering get() { > > return myOrdering.reverse(); > > } > > } > > > -- Kevin Bourrillion @ Google Java Core Libraries Team http://guava-libraries.googlecode.com From henri.gomez at gmail.com Tue May 29 08:57:51 2012 From: henri.gomez at gmail.com (Henri Gomez) Date: Tue, 29 May 2012 17:57:51 +0200 Subject: lambda and jdk8 Message-ID: Hi to all Did there is plan to back ports jdk8 branch back to lambda ? jdk8 and jigsaw are today at b40 whereas lambda is still b35. Cheers From brian.goetz at oracle.com Tue May 29 09:03:07 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 May 2012 12:03:07 -0400 Subject: lambda and jdk8 In-Reply-To: References: Message-ID: <4FC4F33B.2090102@oracle.com> We periodically pull from jdk8 back to lambda. There is no set schedule, but we're probably due for another merge. On 5/29/2012 11:57 AM, Henri Gomez wrote: > Hi to all > > Did there is plan to back ports jdk8 branch back to lambda ? > > jdk8 and jigsaw are today at b40 whereas lambda is still b35. > > Cheers > From maurizio.cimadamore at oracle.com Tue May 29 10:21:44 2012 From: maurizio.cimadamore at oracle.com (maurizio.cimadamore at oracle.com) Date: Tue, 29 May 2012 17:21:44 +0000 Subject: hg: lambda/lambda/langtools: Enable more precise method clash check when sources are compiled using -source 8 (default) Message-ID: <20120529172149.72F1D47596@hg.openjdk.java.net> Changeset: 13262bacbbf2 Author: mcimadamore Date: 2012-05-29 18:21 +0100 URL: http://hg.openjdk.java.net/lambda/lambda/langtools/rev/13262bacbbf2 Enable more precise method clash check when sources are compiled using -source 8 (default) ! src/share/classes/com/sun/tools/javac/code/Source.java ! src/share/classes/com/sun/tools/javac/comp/Check.java ! test/tools/javac/generics/7022054/T7022054pos1.java + test/tools/javac/generics/7022054/T7022054pos1.out ! test/tools/javac/generics/7022054/T7022054pos2.java + test/tools/javac/generics/7022054/T7022054pos2.out From maurizio.cimadamore at oracle.com Tue May 29 10:29:24 2012 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Tue, 29 May 2012 18:29:24 +0100 Subject: Generics oddness In-Reply-To: References: Message-ID: <4FC50774.6040601@oracle.com> Hi I've just pushed a change in the lambda repo that should help in this respect - javac will now generate a more precise error message on the Ordering class declaration, saying that there is a method clash. Maurizio On 29/05/12 16:07, Ben Evans wrote: > Hi, > > At Sunday's Lambdas Hackday, we discovered an issue with Apache > Cassandra's use of Google Guava. > > Specifically, Guava defines an Ordering class which implements Comparator. > > Ordering defines reverse(), which is of course now present on > Comparator, and causes javac to complain: > > This reduces to the following test case: > > public class Ordering implements Comparator { > @Override > public int compare(T o1, T o2) { > // ... > } > > public Ordering reverse() { > // ... > } > } > > public class OrderingMain { > Ordering myOrdering; > > public Ordering get() { > return myOrdering.reverse(); > } > } > > This compiles fine under JDK 7. > > Under JDK 8 Ordering compiles fine. OrderingMain fails with this error: > > hackday1/OrderingMain.java:20: error: reference to reverse is > ambiguous, both method reverse() in Comparator and methodreverse() > in Ordering match > return myOrdering.reverse(); > ^ > where T#1,S,T#2 are type-variables: > T#1 extends Object declared in interface Comparator > S extends T#2 declared in methodreverse() > T#2 extends Object declared in class Ordering > hackday1/OrderingMain.java:20: error: incompatible types > return myOrdering.reverse(); > ^ > required: Ordering > found: Comparator > where T is a type-variable: > T extends Object declared in class OrderingMain > 2 errors > > I've stared at this extensively over the last couple of days, and come > to the conclusion that I don't understand this behaviour. > > Is this a bug? If not, can someone untangle what's happening here for me? > > Thanks, > > Ben > From brian.goetz at oracle.com Tue May 29 14:03:30 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 29 May 2012 17:03:30 -0400 Subject: LJC Lambdas Hackday In-Reply-To: References: Message-ID: <4FC539A2.7020307@oracle.com> > 4. When trying to lambda-ise cassandra it became clear that frequently > you have a list that has multiple responsibilities. If you were to > lambda-ise it, then you?d split things out into multiple calls and > chain them together. This means that in many cases there will be some > refactoring needed in order to introduce lambda usage. Some people > commented that in their workplace the risk of changing reliably > working code outweighs the potential benefits that you?re providing. > Perhaps there?s no good way to address this issue - I certainly have > no suggestions other than getting people to write clean code with high > test coverage so they can easily refactor. Were there examples where you felt "It *should* be easy to lambda-ize this, but I can't figure out how?" These would be useful examples to discuss here. From peter.levart at marand.si Wed May 30 04:28:29 2012 From: peter.levart at marand.si (Peter Levart) Date: Wed, 30 May 2012 13:28:29 +0200 Subject: Generics oddness In-Reply-To: References: <4FC4EDDC.8080603@oracle.com> Message-ID: <12634153.n4duyW0oKJ@peterl.marand.si> On Tuesday, May 29, 2012 08:44:56 AM Kevin Bourrillion wrote: > You might need the parameter that Guava uses anyway -- before we had > it, code like this would not compile: > > Comparator reverseInts = Ordering.natural().reverse(); That's questionable, because it is forgiving to badly written API-s that require Comparator instead of Comparator as a method argument type... Regards, Peter > > > > On Tue, May 29, 2012 at 8:40 AM, Maurizio Cimadamore < > > maurizio.cimadamore at oracle.com> wrote: > > Hi Ben, > > the problem is that there is a clash between two methods that are > > not-override equivalent; one is > > > > class Comparator { > > [...] > > > > Comparator reverse() default { > > > > return Collections.reverseOrder(this); > > > > } > > > > [...] > > } > > > > > > The other one is: > > > > class Ordering implements Comparator { > > > > public Ordering reverse() { > > > > // ... > > > > } > > > > } > > > > As per JLS, this is an illegal override, as Ordering.reverse is not a > > subsignature of Comparator.reverse (as the number of type parameter > > differs). However, I'm investigating as to why the compiler is not > > reporting a clash (as it should). > > > > Thanks > > Maurizio > > > > On 29/05/12 16:07, Ben Evans wrote: > > > public class Ordering implements Comparator { > > > > > > @Override > > > public int compare(T o1, T o2) { > > > > > > // ... > > > > > > } > > > > > > public Ordering reverse() { > > > > > > // ... > > > > > > } > > > > > > } > > > > > > public class OrderingMain { > > > > > > Ordering myOrdering; > > > > > > public Ordering get() { > > > > > > return myOrdering.reverse(); > > > > > > } > > > > > > } From brian.goetz at oracle.com Wed May 30 12:29:36 2012 From: brian.goetz at oracle.com (brian.goetz at oracle.com) Date: Wed, 30 May 2012 19:29:36 +0000 Subject: hg: lambda/lambda/jdk: 3 new changesets Message-ID: <20120530193030.4C17347622@hg.openjdk.java.net> Changeset: b0c33c2eb0a9 Author: briangoetz Date: 2012-05-30 15:25 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/b0c33c2eb0a9 Minor doc tweaks ! src/share/classes/java/lang/invoke/LambdaMetafactory.java Changeset: b30865c62616 Author: briangoetz Date: 2012-05-30 15:26 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/b30865c62616 Update to latest testng ! test-ng/build.xml Changeset: f0554992d9c5 Author: briangoetz Date: 2012-05-30 15:29 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/f0554992d9c5 7172553: A utility class that forms the basis of a String.join() operation Summary: A class which will support String.join() that complements lambda changes Reviewed-by: smarks, briangoetz, psandoz Contributed-by: jgish ! make/java/java/FILES_java.gmk ! makefiles/java/java/FILES_java.gmk + src/share/classes/java/util/StringJoiner.java + test-ng/tests/org/openjdk/tests/java/util/StringJoinerTest.java From forax at univ-mlv.fr Wed May 30 15:00:57 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Thu, 31 May 2012 00:00:57 +0200 Subject: hg: lambda/lambda/jdk: 3 new changesets In-Reply-To: <20120530193030.4C17347622@hg.openjdk.java.net> References: <20120530193030.4C17347622@hg.openjdk.java.net> Message-ID: <4FC69899.7090704@univ-mlv.fr> On 05/30/2012 09:29 PM, brian.goetz at oracle.com wrote: > Changeset: b0c33c2eb0a9 > Author: briangoetz > Date: 2012-05-30 15:25 -0400 > URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/b0c33c2eb0a9 > > Minor doc tweaks > > ! src/share/classes/java/lang/invoke/LambdaMetafactory.java > > Changeset: b30865c62616 > Author: briangoetz > Date: 2012-05-30 15:26 -0400 > URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/b30865c62616 > > Update to latest testng > > ! test-ng/build.xml > > Changeset: f0554992d9c5 > Author: briangoetz > Date: 2012-05-30 15:29 -0400 > URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/f0554992d9c5 > > 7172553: A utility class that forms the basis of a String.join() operation > Summary: A class which will support String.join() that complements lambda changes > Reviewed-by: smarks, briangoetz, psandoz > Contributed-by: jgish > > ! make/java/java/FILES_java.gmk > ! makefiles/java/java/FILES_java.gmk > + src/share/classes/java/util/StringJoiner.java > + test-ng/tests/org/openjdk/tests/java/util/StringJoinerTest.java > > I don't like the class StringJoiner because despite the fact it's a reduce operation, it's implemented as a Fillable, so something eager which will not work as is in the parallel world. I think it's better to add join() on Iterable. R?mi From brian.goetz at oracle.com Wed May 30 15:11:38 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 30 May 2012 18:11:38 -0400 Subject: hg: lambda/lambda/jdk: 3 new changesets In-Reply-To: <4FC69899.7090704@univ-mlv.fr> References: <20120530193030.4C17347622@hg.openjdk.java.net> <4FC69899.7090704@univ-mlv.fr> Message-ID: <4FC69B1A.2040208@oracle.com> > I don't like the class StringJoiner because despite the fact it's a > reduce operation, > it's implemented as a Fillable, so something eager which will not work > as is in the parallel world. That's where we started -- trying to treat string joining as a reduce. But because String is immutable, doing a sequential reduce with string concatenation becomes an O(n^2) operation, which is not good. (Originally we thought that the way to do joining was: stream.interleaveWith(Streams.repeating(", ")) .reduce(String::concatenate) but the reduce step, which, while pretty, was inefficient.) The parallel case isn't much better. Even if you do a number of string joins at the leaves of the tree, the top-level combine still has to copy all the string content, which loses most of the parallelism. But you can still do upstream ops in parallel: collection.parallel() .filter(...) .map(...) .sorted() .sequential() .into(new StringJoiner(", ")); and all the upstream stuff will happen in parallel. > I think it's better to add join() on Iterable. Would like to, but we can't add methods that only apply to specific parameterizations. From forax at univ-mlv.fr Wed May 30 16:26:42 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Thu, 31 May 2012 01:26:42 +0200 Subject: hg: lambda/lambda/jdk: 3 new changesets In-Reply-To: <4FC69B1A.2040208@oracle.com> References: <20120530193030.4C17347622@hg.openjdk.java.net> <4FC69899.7090704@univ-mlv.fr> <4FC69B1A.2040208@oracle.com> Message-ID: <4FC6ACB2.2000709@univ-mlv.fr> On 05/31/2012 12:11 AM, Brian Goetz wrote: >> I don't like the class StringJoiner because despite the fact it's a >> reduce operation, >> it's implemented as a Fillable, so something eager which will not work >> as is in the parallel world. > > That's where we started -- trying to treat string joining as a reduce. > But because String is immutable, doing a sequential reduce with string > concatenation becomes an O(n^2) operation, which is not good. > > (Originally we thought that the way to do joining was: > stream.interleaveWith(Streams.repeating(", ")) > .reduce(String::concatenate) > but the reduce step, which, while pretty, was inefficient.) join is a kind reduce operation that can be easily be implemented as a foldLeft on a StringBuilder. collection.foldLeft(new StringBuilder(), (element, builder) -> { if (builder.length == 0) return builder.append(element); return builder.append(", ").append(element); }).toString() for the parallel case, the question is how to implement foldLeft ? perhaps foldLeft should return an Iterable of StringBuilder() that you can reduce sequentially afterward. > > The parallel case isn't much better. Even if you do a number of > string joins at the leaves of the tree, the top-level combine still > has to copy all the string content, which loses most of the parallelism. > > But you can still do upstream ops in parallel: > > collection.parallel() > .filter(...) > .map(...) > .sorted() > .sequential() > .into(new StringJoiner(", ")); > > and all the upstream stuff will happen in parallel. > >> I think it's better to add join() on Iterable. > > Would like to, but we can't add methods that only apply to specific > parameterizations. you don't have to because all objects have a method toString() or said in another way StringBuilder.append() takes an Object as parameter. cheers, R?mi From brian.goetz at oracle.com Wed May 30 16:31:36 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 30 May 2012 19:31:36 -0400 Subject: hg: lambda/lambda/jdk: 3 new changesets In-Reply-To: <4FC6ACB2.2000709@univ-mlv.fr> References: <20120530193030.4C17347622@hg.openjdk.java.net> <4FC69899.7090704@univ-mlv.fr> <4FC69B1A.2040208@oracle.com> <4FC6ACB2.2000709@univ-mlv.fr> Message-ID: <4FC6ADD8.9080901@oracle.com> Note also that StringJoiner will be used in the implementation of the upcoming (long-requested!) String.join methods, and can be used to implement various toString implementations more easily. On 5/30/2012 7:26 PM, R?mi Forax wrote: > On 05/31/2012 12:11 AM, Brian Goetz wrote: >>> I don't like the class StringJoiner because despite the fact it's a >>> reduce operation, >>> it's implemented as a Fillable, so something eager which will not work >>> as is in the parallel world. >> >> That's where we started -- trying to treat string joining as a reduce. >> But because String is immutable, doing a sequential reduce with string >> concatenation becomes an O(n^2) operation, which is not good. >> >> (Originally we thought that the way to do joining was: >> stream.interleaveWith(Streams.repeating(", ")) >> .reduce(String::concatenate) >> but the reduce step, which, while pretty, was inefficient.) > > join is a kind reduce operation that can be easily be implemented as a > foldLeft > on a StringBuilder. > > collection.foldLeft(new StringBuilder(), > (element, builder) -> { > if (builder.length == 0) > return builder.append(element); > return builder.append(", ").append(element); > }).toString() > > for the parallel case, the question is how to implement foldLeft ? > perhaps foldLeft should return an Iterable of StringBuilder() that you can > reduce sequentially afterward. > >> >> The parallel case isn't much better. Even if you do a number of string >> joins at the leaves of the tree, the top-level combine still has to >> copy all the string content, which loses most of the parallelism. >> >> But you can still do upstream ops in parallel: >> >> collection.parallel() >> .filter(...) >> .map(...) >> .sorted() >> .sequential() >> .into(new StringJoiner(", ")); >> >> and all the upstream stuff will happen in parallel. >> >>> I think it's better to add join() on Iterable. >> >> Would like to, but we can't add methods that only apply to specific >> parameterizations. > > you don't have to because all objects have a method toString() > or said in another way StringBuilder.append() takes an Object as parameter. > > cheers, > R?mi > > > From forax at univ-mlv.fr Wed May 30 16:41:32 2012 From: forax at univ-mlv.fr (=?ISO-8859-1?Q?R=E9mi_Forax?=) Date: Thu, 31 May 2012 01:41:32 +0200 Subject: hg: lambda/lambda/jdk: 3 new changesets In-Reply-To: <4FC6ADD8.9080901@oracle.com> References: <20120530193030.4C17347622@hg.openjdk.java.net> <4FC69899.7090704@univ-mlv.fr> <4FC69B1A.2040208@oracle.com> <4FC6ACB2.2000709@univ-mlv.fr> <4FC6ADD8.9080901@oracle.com> Message-ID: <4FC6B02C.10405@univ-mlv.fr> On 05/31/2012 01:31 AM, Brian Goetz wrote: > Note also that StringJoiner will be used in the implementation of the > upcoming (long-requested!) String.join methods, and can be used to > implement various toString implementations more easily. I know that this has been requested a long time ago because I've written a patch for that 2 or 3 years ago (at least). But why String.join(separator, iterable) can't just call iterable.foldleft(...).toString() ? R?mi > > > > On 5/30/2012 7:26 PM, R?mi Forax wrote: >> On 05/31/2012 12:11 AM, Brian Goetz wrote: >>>> I don't like the class StringJoiner because despite the fact it's a >>>> reduce operation, >>>> it's implemented as a Fillable, so something eager which will not work >>>> as is in the parallel world. >>> >>> That's where we started -- trying to treat string joining as a reduce. >>> But because String is immutable, doing a sequential reduce with string >>> concatenation becomes an O(n^2) operation, which is not good. >>> >>> (Originally we thought that the way to do joining was: >>> stream.interleaveWith(Streams.repeating(", ")) >>> .reduce(String::concatenate) >>> but the reduce step, which, while pretty, was inefficient.) >> >> join is a kind reduce operation that can be easily be implemented as a >> foldLeft >> on a StringBuilder. >> >> collection.foldLeft(new StringBuilder(), >> (element, builder) -> { >> if (builder.length == 0) >> return builder.append(element); >> return builder.append(", ").append(element); >> }).toString() >> >> for the parallel case, the question is how to implement foldLeft ? >> perhaps foldLeft should return an Iterable of StringBuilder() that >> you can >> reduce sequentially afterward. >> >>> >>> The parallel case isn't much better. Even if you do a number of string >>> joins at the leaves of the tree, the top-level combine still has to >>> copy all the string content, which loses most of the parallelism. >>> >>> But you can still do upstream ops in parallel: >>> >>> collection.parallel() >>> .filter(...) >>> .map(...) >>> .sorted() >>> .sequential() >>> .into(new StringJoiner(", ")); >>> >>> and all the upstream stuff will happen in parallel. >>> >>>> I think it's better to add join() on Iterable. >>> >>> Would like to, but we can't add methods that only apply to specific >>> parameterizations. >> >> you don't have to because all objects have a method toString() >> or said in another way StringBuilder.append() takes an Object as >> parameter. >> >> cheers, >> R?mi >> >> >> From pbenedict at apache.org Wed May 30 18:08:03 2012 From: pbenedict at apache.org (Paul Benedict) Date: Wed, 30 May 2012 20:08:03 -0500 Subject: Method reference double-colon syntax Message-ID: > I'm pretty sure this is covered in the mailing list archives - M I checked. The compiler changes occurred in February but no justification given. I am not looking to judge the justification; just wondering how they justified :: that was better than #. Paul From keith.mcguigan at oracle.com Wed May 30 19:00:44 2012 From: keith.mcguigan at oracle.com (keith.mcguigan at oracle.com) Date: Thu, 31 May 2012 02:00:44 +0000 Subject: hg: lambda/lambda/hotspot: Summary: Fix occasional AME problem and add more tracing Message-ID: <20120531020052.405114763A@hg.openjdk.java.net> Changeset: ffb9316fd9ed Author: kamg Date: 2012-05-30 17:27 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/ffb9316fd9ed Summary: Fix occasional AME problem and add more tracing ! src/share/vm/classfile/defaultMethods.cpp ! src/share/vm/oops/instanceKlass.cpp From brian.goetz at oracle.com Wed May 30 19:43:28 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 30 May 2012 22:43:28 -0400 Subject: Method reference double-colon syntax In-Reply-To: References: Message-ID: <4FC6DAD0.2000601@oracle.com> > I checked. The compiler changes occurred in February but no > justification given. I am not looking to judge the justification; just > wondering how they justified :: that was better than #. There were a number of reasons. No one thinks :: is perfect, but # is worse, and there were many other alternatives explored that were rejected for various technical reasons. (Others may disagree with the conclusions or the reasons -- you have a right to -- but let's not dive down that rathole.) The prototype implementation used the following syntax for method references: Foo#bar. This made sense mostly because the lambda syntax used #, and secondarily (way distant second) that the Javadoc syntax for methods was Foo#bar. With the change in lambda syntax to one that does not use a #, the first no longer applies. The Javadoc justification is in actuality pretty weak; I would hazard that only a few percent of Java developers have used it, and if you quizzed developers on "what is the pound symbol used for in Java", most would say "nothing". The Javadoc use is more of a post-hoc justification than a real reason to choose it. It would have been desirable for the lambda syntax to be similar to the method reference syntax. Foo->bar seems really good, until you realize it is unworkable; with the optional generic type arguments (on both sides of the delimiter, just like with dot), you could get Foo->bar or Foo->bar or worst, Foo->bar. Oops. (Maybe with good syntax coloring that might be readable.) It turns out that the obvious prefix syntaxes, such as &Foo.bar were syntactically ambiguous with other constructs. Obvious other candidates for infix delimiters (including : and .) also fail for various reasons. There were many other candidates proposed, such as backtick (`Foo.bar) or compound infix delimiters (Foo&.bar) but no one could get behind these. That doesn't leave many credible choices. Using # as an infix syntax is questionable. While there is room for opinion to vary, # is more of a "naturally prefix" syntax than a "naturally infix" syntax, whereas :: is more of a "naturally infix" syntax. (Look at their use in other languages.) The real knock against :: is "ugh, looks like C++", but if we ruled out any construct that was used in any other language with which people might have had a bad experience, we'd need to get much bigger keyboards. (And, in actuality, using :: in method references is related to namespacing, so the C++ connection might actually be a positive hint.) Given all this, the deciding factor turned out to be global syntactic real estate management. There is a significant hidden cost to picking a syntax: using a syntactic form for one feature may foreclose on using elements of that form for other, possibly more "deserving" features. As stewards, we have a responsibility not only to deliver language improvements that use pleasant syntax, but also to do global syntactic real estate management, otherwise we cripple our ability to continue to evolve the language without being undermined by silly syntactic roadblocks. There are darn few unsullied characters left; # is one of the few good ones. Using # for lambdas+method references might have made sense; then # can be thought of as the "delayed evaluation" operator, and the two uses reinforce each other. That's at least a biggish payback for using our last bit of virgin symbology. Using it for method references only is less of a payback. Far less. Like paying for a hamburger with a Rolex. To illustrate what I mean by "we could do better", here's an alternative proposal that gets far more mileage out of #: structured literals. While these plans are not in place for 8, we have already stated our desire to add structured literals for lists, maps, sets, etc. # as a prefix symbol, combined with delimiters, gives us a far higher return-on-syntax as a structured literal builder (as a bonus, # is already associated with structured literals in a lot of languages, going all the way back to many early assembly languages where # was the immediate addressing mode.) For example: #[ 1, 2, 3 ] // Array, list, set #{ "foo" : "bar", "blah" : "wooga" } // Map literals #/(\d+)$/ // Regex #(a, b) // Tuple #(a: 3, b: 4) // Record #"There are {foo.size()} foos" // String literal Not that we'd embrace all of these immediately (or ever), but the point is: there's a lot of room for expansion, unlike using # for MRs only. (We can use target typing to distinguish between array, set, list literals (even JSON literals)). Much more bang for the pound. The :: infix syntax: ClassName::methodName ClassName::methodName ClassName::genericMethodName works acceptably well. Some people like it, and some people hate it -- just like #. There's never going to be a perfect syntax for anything that makes everyone jump up in unison and say "yeah, that's it!" But :: is OK, and using up :: here is far better than using up #. (And, while this might look a little weird to C++ programmers, the overlap between the Java and C++ developer bases at this point is small enough that I don't think we should be too worried about that.) From jack at moxley.co.uk Wed May 30 23:27:20 2012 From: jack at moxley.co.uk (Jack Moxley) Date: Thu, 31 May 2012 07:27:20 +0100 Subject: Method reference double-colon syntax In-Reply-To: <4FC6DAD0.2000601@oracle.com> References: <4FC6DAD0.2000601@oracle.com> Message-ID: I don't want to be pedantic, but if you don't mind referring to # as the hash symbol instead in future correspondence / mail. Otherwise your going to confuse every British developer out there all of whom refer to ? as the pound symbol. Sent from my iPhone On 31 May 2012, at 03:43, Brian Goetz wrote: > what is the pound symbol used > for in Java", most would say "nothing". From joe.darcy at oracle.com Wed May 30 23:39:43 2012 From: joe.darcy at oracle.com (Joe Darcy) Date: Wed, 30 May 2012 23:39:43 -0700 Subject: Method reference double-colon syntax In-Reply-To: References: <4FC6DAD0.2000601@oracle.com> Message-ID: <4FC7122F.1090508@oracle.com> The most proper term for the "#" character is octothorpe :-) http://en.wikipedia.org/wiki/Number_sign -Joe On 5/30/2012 11:27 PM, Jack Moxley wrote: > I don't want to be pedantic, but if you don't mind referring to # as the hash symbol instead in future correspondence / mail. > > Otherwise your going to confuse every British developer out there all of whom refer to ? as the pound symbol. > > Sent from my iPhone > > On 31 May 2012, at 03:43, Brian Goetz wrote: > >> what is the pound symbol used >> for in Java", most would say "nothing". > From alex.blewitt at gmail.com Wed May 30 23:50:40 2012 From: alex.blewitt at gmail.com (Alex Blewitt) Date: Thu, 31 May 2012 07:50:40 +0100 Subject: Method reference double-colon syntax In-Reply-To: <4FC6DAD0.2000601@oracle.com> References: <4FC6DAD0.2000601@oracle.com> Message-ID: <0C1DADDB-1472-41EE-930A-B4B3F6BC5FCD@gmail.com> On 31 May 2012, at 03:43, Brian Goetz wrote: > For example: > > #[ 1, 2, 3 ] // Array, list, set > #{ "foo" : "bar", "blah" : "wooga" } // Map literals > #/(\d+)$/ // Regex > #(a, b) // Tuple > #(a: 3, b: 4) // Record > #"There are {foo.size()} foos" // String literal I'm sure it was noted when these considerations were given, but Objective-C recently added map and array literals http://stackoverflow.com/questions/9693647/is-there-some-literal-dictionary-or-array-syntax-in-objective-c Their syntax uses @{} and @[] for the prefix character (though objc has a history of @ precluding these specific use cases). I suspect the same could work for Java as well, and with objc's growing popularity this might be a good synergistic use. I for one preferred the hash (#) since I'm one of the few Java developers that uses it for JavaDoc. Alex From sven at efftinge.de Thu May 31 00:04:32 2012 From: sven at efftinge.de (Sven Efftinge) Date: Thu, 31 May 2012 09:04:32 +0200 Subject: Method reference double-colon syntax In-Reply-To: <4FC6DAD0.2000601@oracle.com> References: <4FC6DAD0.2000601@oracle.com> Message-ID: On May 31, 2012, at 4:43 AM, Brian Goetz wrote: > With the change in lambda syntax to one that does not use a #, the first > no longer applies. The Javadoc justification is in actuality pretty > weak; I would hazard that only a few percent of Java developers have > used it, and if you quizzed developers on "what is the pound symbol used > for in Java", most would say "nothing". The Javadoc use is more of a > post-hoc justification than a real reason to choose it. At least in the teams I have worked with everybody reads JavaDoc a lot. It's an important part of the language. Another way to use the # in a future release would be to introduce literals for members of classes. I.e. 'String#length' would be an expression of type java.lang.reflect.Method. This would also be more in line with how the # is used in JavaDoc. Unfortunately people would get confused by the subtile differences between method literals and a method references. Sven From scolebourne at joda.org Thu May 31 00:19:03 2012 From: scolebourne at joda.org (Stephen Colebourne) Date: Thu, 31 May 2012 08:19:03 +0100 Subject: Method reference double-colon syntax In-Reply-To: <4FC6DAD0.2000601@oracle.com> References: <4FC6DAD0.2000601@oracle.com> Message-ID: Thanks for the explanation. Its good to know that there is some rationale, even though I disagree. I continue to think using # for both lamdbas and references was the best option. Thats because it read well, linked related features together, and gave the necessary visual clue to to readers that something interesting is going on. I also dislike two character operators. All I can say is that I hope Eclipse allows me to colour the -> and :: so that I can actually see them. Oh, and extended literals/sub-language would probably be a good thing. I'm sure I've mentioned using $ as a prefix to get an "expression language" embedded in Java (with different null-handling behaviour) before. Stephen On 31 May 2012 03:43, Brian Goetz wrote: >> I checked. The compiler changes occurred in February but no >> justification given. I am not looking to judge the justification; just >> wondering how they justified :: that was better than #. > > There were a number of reasons. ?No one thinks :: is perfect, but # is > worse, and there were many other alternative explored that were > rejected for various technical reasons. ?(Others may disagree with the > conclusions or the reasons -- you have a right to -- but let's not dive > down that rathole.) > > The prototype implementation used the following syntax for method > references: Foo#bar. ?This made sense mostly because the lambda syntax > used #, and secondarily (way distant second) that the Javadoc syntax for > methods was Foo#bar. > > With the change in lambda syntax to one that does not use a #, the first > no longer applies. ?The Javadoc justification is in actuality pretty > weak; I would hazard that only a few percent of Java developers have > used it, and if you quizzed developers on "what is the pound symbol used > for in Java", most would say "nothing". ?The Javadoc use is more of a > post-hoc justification than a real reason to choose it. > > It would have been desirable for the lambda syntax to be similar to the > method reference syntax. ?Foo->bar seems really good, until you realize > it is unworkable; with the optional generic type arguments (on both > sides of the delimiter, just like with dot), you could get Foo->bar > or Foo->bar or worst, Foo->bar. ?Oops. ?(Maybe with good syntax > coloring that might be readable.) > > It turns out that the obvious prefix syntaxes, such as &Foo.bar were > syntactically ambiguous with other constructs. ?Obvious other candidates > for infix delimiters (including : and .) also fail for various reasons. > ?There were many other candidates proposed, such as backtick (`Foo.bar) > or compound infix delimiters (Foo&.bar) but no one could get behind these. > > That doesn't leave many credible choices. > > Using # as an infix syntax is questionable. ?While there is room for > opinion to vary, # is more of a "naturally prefix" syntax than a > "naturally infix" syntax, whereas :: is more of a "naturally infix" > syntax. ?(Look at their use in other languages.) ?The real knock against > :: is "ugh, looks like C++", but if we ruled out any construct that was > used in any other language with which people might have had a bad > experience, we'd need to get much bigger keyboards. ?(And, in actuality, > using :: in method references is related to namespacing, so the C++ > connection might actually be a positive hint.) > > Given all this, the deciding factor turned out to be global syntactic > real estate management. ?There is a significant hidden cost to picking a > syntax: using a syntactic form for one feature may foreclose on using > elements of that form for other, possibly more "deserving" features. ?As > stewards, we have a responsibility not only to deliver language > improvements that use pleasant syntax, but also to do global syntactic > real estate management, otherwise we cripple our ability to continue to > evolve the language without being undermined by silly syntactic > roadblocks. ?There are darn few unsullied characters left; # is one of > the few good ones. > > Using # for lambdas+method references might have made sense; then # can > be thought of as the "delayed evaluation" operator, and the two uses > reinforce each other. ?That's at least a biggish payback for using our > last bit of virgin symbology. ?Using it for method references only is > less of a payback. ?Far less. ?Like paying for a hamburger with a Rolex. > > To illustrate what I mean by "we could do better", here's an alternative > proposal that gets far more mileage out of #: structured literals. > While these plans are not in place for 8, we have already stated our > desire to add structured literals for lists, maps, sets, etc. ?# as a > prefix symbol, combined with delimiters, gives us a far higher > return-on-syntax as a structured literal builder (as a bonus, # is > already associated with structured literals in a lot of languages, going > all the way back to many early assembly languages where # was the > immediate addressing mode.) ?For example: > > #[ 1, 2, 3 ] ? ? ? ? ? ? ? ? ? ? ? ? ?// Array, list, set > #{ "foo" : "bar", "blah" : "wooga" } ?// Map literals > #/(\d+)$/ ? ? ? ? ? ? ? ? ? ? ? ? ? ? // Regex > #(a, b) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // Tuple > #(a: 3, b: 4) ? ? ? ? ? ? ? ? ? ? ? ? // Record > #"There are {foo.size()} foos" ? ? ? ?// String literal > > Not that we'd embrace all of these immediately (or ever), but the point > is: there's a lot of room for expansion, unlike using # for MRs only. > (We can use target typing to distinguish between array, set, list > literals (even JSON literals)). ?Much more bang for the pound. > > The :: infix syntax: > > ? ClassName::methodName > ? ClassName::methodName > ? ClassName::genericMethodName > > works acceptably well. ?Some people like it, and some people hate it -- > just like #. ?There's never going to be a perfect syntax for anything > that makes everyone jump up in unison and say "yeah, that's it!" ?But :: > is OK, and using up :: here is far better than using up #. ?(And, while > this might look a little weird to C++ programmers, the overlap between > the Java and C++ developer bases at this point is small enough that I > don't think we should be too worried about that.) > > From oleksander.demura at gmail.com Thu May 31 00:42:08 2012 From: oleksander.demura at gmail.com (Olexandr Demura) Date: Thu, 31 May 2012 10:42:08 +0300 Subject: hg: lambda/lambda/jdk: 3 new changesets Message-ID: Ropes to the rescue? http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf http://ahmadsoft.org/ropes/ >> I don't like the class StringJoiner because despite the fact it's a >> reduce operation, >> it's implemented as a Fillable, so something eager which will not work >> as is in the parallel world. > >That's where we started -- trying to treat string joining as a reduce. >But because String is immutable, doing a sequential reduce with string >concatenation becomes an O(n^2) operation, which is not good. > >(Originally we thought that the way to do joining was: > ? stream.interleaveWith(Streams.repeating(", ")) > ? ? ? ? .reduce(String::concatenate) >but the reduce step, which, while pretty, was inefficient.) > >The parallel case isn't much better. ?Even if you do a number of string >joins at the leaves of the tree, the top-level combine still has to copy >all the string content, which loses most of the parallelism. > >But you can still do upstream ops in parallel: > > ?collection.parallel() > ? ? ? ? ? ?.filter(...) > ? ? ? ? ? ?.map(...) > ? ? ? ? ? ?.sorted() > ? ? ? ? ? ?.sequential() > ? ? ? ? ? ?.into(new StringJoiner(", ")); > >and all the upstream stuff will happen in parallel. > >> I think it's better to add join() on Iterable. > >Would like to, but we can't add methods that only apply to specific >parameterizations. From brian.goetz at oracle.com Thu May 31 06:17:36 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 31 May 2012 09:17:36 -0400 Subject: Method reference double-colon syntax In-Reply-To: References: <4FC6DAD0.2000601@oracle.com> Message-ID: <4FC76F70.70703@oracle.com> I always wondered which came first: that they shared the same key position on US/UK keyboards, or that they shared the name. Chicken? Egg? On 5/31/2012 2:27 AM, Jack Moxley wrote: > I don't want to be pedantic, but if you don't mind referring to # as the hash symbol instead in future correspondence / mail. > > Otherwise your going to confuse every British developer out there all of whom refer to ? as the pound symbol. > > Sent from my iPhone > > On 31 May 2012, at 03:43, Brian Goetz wrote: > >> what is the pound symbol used >> for in Java", most would say "nothing". > From brian.goetz at oracle.com Thu May 31 06:22:35 2012 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 31 May 2012 09:22:35 -0400 Subject: Method reference double-colon syntax In-Reply-To: References: <4FC6DAD0.2000601@oracle.com> Message-ID: <4FC7709B.1040609@oracle.com> > Another way to use the # in a future release would be to introduce literals for members of classes. Well-covered ground. Through target typing, it would indeed be possible to convert method references (Foo::bar) into Method objects or MethodHandle objects. (The same syntax can be extended to fields being converted to Field objects.) We've chosen to not do so for 8, but were careful to leave room for this in the future. From matthew at matthewadams.me Thu May 31 09:21:27 2012 From: matthew at matthewadams.me (Matthew Adams) Date: Thu, 31 May 2012 11:21:27 -0500 Subject: Method reference double-colon syntax In-Reply-To: <4FC7709B.1040609@oracle.com> References: <4FC6DAD0.2000601@oracle.com> <4FC7709B.1040609@oracle.com> Message-ID: This one is crucial for me. I'm sad to hear it won't be in 8. Is it currently targeted for 9? Can I get an "8.1"? ;) On Thu, May 31, 2012 at 8:22 AM, Brian Goetz wrote: > > Another way to use the # in a future release would be to introduce > literals for members of classes. > > Well-covered ground. Through target typing, it would indeed be possible > to convert method references (Foo::bar) into Method objects or > MethodHandle objects. (The same syntax can be extended to fields being > converted to Field objects.) We've chosen to not do so for 8, but were > careful to leave room for this in the future. > > > > -- @matthewadams12 mailto:matthew at matthewadams.me skype:matthewadams12 yahoo:matthewadams aol:matthewadams12 google-talk:matthewadams12 at gmail.com msn:matthew at matthewadams.me http://matthewadams.me http://www.linkedin.com/in/matthewadams From keith.mcguigan at oracle.com Thu May 31 10:50:08 2012 From: keith.mcguigan at oracle.com (keith.mcguigan at oracle.com) Date: Thu, 31 May 2012 17:50:08 +0000 Subject: hg: lambda/lambda/jdk: Summary: Regression test for hotspot lost overloaded method bug Message-ID: <20120531175037.E9E7F47650@hg.openjdk.java.net> Changeset: 75dd44c03e74 Author: kamg Date: 2012-05-31 14:00 -0400 URL: http://hg.openjdk.java.net/lambda/lambda/jdk/rev/75dd44c03e74 Summary: Regression test for hotspot lost overloaded method bug + test-ng/tests/org/openjdk/tests/vm/DefaultMethodRegressionTests.java From jim.gish at oracle.com Thu May 31 11:00:53 2012 From: jim.gish at oracle.com (Jim Gish) Date: Thu, 31 May 2012 14:00:53 -0400 Subject: problematic libjdwp.so in lambda build Message-ID: <4FC7B1D5.2030204@oracle.com> While attempting to use lambda builds with netbeans, I found that the libjdwp.so being built with "make images" in lambda cannot be opened. I was able to substitute the library from the mainline jdk8 build and use that with no problem, but there is some issue with the version being built under lambda. The output from "make images" doesn't reveal anything unusual that I can see (but then I've not looked at these before now): Checking for mapfile use in: /jdk/lambda/lambda/build/linux-ia32-normal-clientANDserver-release/images/j2sdk-image/jre/lib/i386/libjdwp.so Library loads for: /jdk/lambda/lambda/build/linux-ia32-normal-clientANDserver-release/images/j2sdk-image/jre/lib/i386/libjdwp.so linux-gate.so.1 => (0x40022000) libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0x40081000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40086000) /lib/ld-linux.so.2 (0x40000000) RUNPATH for: /jdk/lambda/lambda/build/linux-ia32-normal-clientANDserver-release/images/j2sdk-image/jre/lib/i386/libjdwp.so 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libc.so.6] The output from netbeans debug is: NPT ERROR: Cannot open library Java Result: 1 Of course you don't need netbeans to reproduce this since it's just invoking java using -Xrunjdwp (which looks like it should be updated to the new option): Execute:Java13CommandLauncher: Executing '/jdk/lambda/lambda/build/linux-ia32-normal-clientANDserver-release/images/j2sdk-image/bin/java' with arguments: '-Xrunjdwp:transport=dt_socket,address=localhost:48444' '-classpath' '/home/jgish/NetBeansProjects/lambda-tests/build/classes:/tools/netbeans/platform/modules/ext/junit-4.8.2.jar:/tools/netbeans/platform/modules/ext/testng-6.5.1-dist.jar:/home/jgish/NetBeansProjects/lambda-tests/build/test/classes' 'org.testng.TestNG' '-mixed' '-d' '/tmp/org.openjdk.tests.java.util.StringJoinerTest' '-listener' 'org.testng.reporters.VerboseReporter' '-testclass' 'org.openjdk.tests.java.util.StringJoinerTest' The ' characters around the executable and arguments are not part of the command. NPT ERROR: Cannot open library Java Result: 1 I just thought someone might to dig deeper and find out what's going on and fix it. Thanks, Jim