Re: [commons-lang] Comments on new FunctionUtils / nested lambda feature
The function() method is a great technique, it's now in Functions and FailableFunction (git master). I'll see later if it can be used within Lang. I know I can use it in other projects. Wrt an API for a vararg of functions that implements chaining internally, I'm not so sure. I've though I needed something like that in past, but I've always ended up with other coding patterns I found better at the time for whatever reason.. Gary Gary On Fri, Aug 4, 2023, 3:24 PM Gary Gregory wrote: > Worth adding adding function(Function)? Seems low cost to add it > FailableFunction. > > Gary > > On Fri, Aug 4, 2023, 2:04 PM Rob Spoor wrote: > >> With just one simple utility method you can get all the chaining you want: >> >> public static Function function(Function func) { >> return func; >> } >> >> This doesn't look very useful, but it allows you to turn a method >> reference or lambda into a typed Function without needing a cast. After >> that it's really simple using what's provided in the Java API: >> >> Function func = function(MyBean::getChild) >> .andThen(Child::getName); >> >> You want a default value? Almost just as easy: >> >> someFrameworkThing.setProperty(function(ParentBean::getChild) >> .andThen(ChildBean::getName) >> .andThen(Optional::ofNullable) >> .andThen(o -> o.orElse("defaultName")); >> >> >> On 04/08/2023 16:04, Daniel Watson wrote: >> > Asking for comments and thoughts on a potential new feature. Already >> > developed in a commons-like style, but dont want to submit PR without >> > discussion as it may be considered out of scope or too use case >> specific. >> > >> > Justification and details... >> > >> > I've run into a scenario a few times where nested lamba functions would >> be >> > incredibly useful. e.g. >> > >> > MyBean::getChild::getName >> > >> > Obviously this is not a language feature, but can be simulated in a >> useful >> > way. So far my use has mostly been related to code that works with POJO >> > beans, and frameworks that use function references to understand those >> > beans and properties. Specifically useful where the context of the code >> > block is the parent entity, but you need to reference a child, and >> without >> > nested lambdas you end up with things like the below... >> > >> > ParentBean parentBean = new ParentBean(); >> > parentBean.setChild(new ChildBean("name")); >> > //imagine that FrameworkThing is a generic class, and thus the generic >> type >> > is ParentBean >> > FrameworkThing someFrameworkThing = new FrameworkThing >> (ParentBean.class) >> > //but we need to get to a property of a child bean >> > someFrameworkThing.setProperty((parentBean) -> { >> > >> > return parentBean.getChild().getName(); >> > >> > }); >> > >> > Obviously this could be handled with a getChildName() method on the >> parent >> > bean, but that has pitfalls as well (e.g. bean class cannot be changed, >> or >> > adding of properties interferes with other usage of the class e.g. JPA, >> > JAX). However with a util class the second call can be reduced to >> > something like below, leaving the bean API untouched. >> > >> > >> someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName)); >> > >> > Taken alone, that single reduction may seem trivial, but in a scenario >> > where these nested references are commonly needed, the reduction makes >> the >> > code clearer (In my opinion), as it is immediately apparent on a single >> > line of code that the reference is a simple nested property, rather than >> > having to interpret an inline lambda function. It also discourages >> errant >> > placement of code by avoiding the inline function (since the only >> purpose >> > of the lambda was to retrieve a single nested value). In addition, If >> > intermediate nulls need to be handled then the reduction becomes more >> > apparent, as the null checks can be handled in the util class rather >> than >> > cluttering the app code. e.g. >> > >> > >> someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,"defaultName")); >> > //or... >> > >> someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,null)); >> > >> > The third parameter here is a String (typed genetically based on the >> return >> > type of getName) and indicates the default value to be returned if the >> > first call to getChild() returns null. e.g. it replaces something >> like... >> > >> > someFrameworkThing.setProperty((parentBean) -> { >> > >> > ChildBean cb = parentBean.getChild(); >> > if(cb == null) return null; //or other default value >> > else return cb.getName(); >> > >> > }); >> > >> > Given that commons-lang aims to extend existing language features, this >> > seemed like a reasonable place for a nested lambda util class. So far my >> > concerns are... >> > >> > 1. Does this feel too specific to an application to warrant >>
Re: [VOTE] Release Apache Commons DbUtils 1.8.0 based on RC1
Thanks Rob! Gary On Fri, Aug 4, 2023, 4:13 PM Rob Tompkins wrote: > All looks approriate > signatures ok > build ok on java 8, 11, 17 > reports look good. > > Send it! > > +1 > > > On Aug 1, 2023, at 8:40 PM, Gary Gregory wrote: > > > > We have fixed a few bugs and added some enhancements since Apache > > Commons DbUtils 1.7 was released, so I would like to release Apache > > Commons DbUtils 1.8.0. > > > > Apache Commons DbUtils 1.8.0 RC1 is available for review here: > >https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1 > > (svn revision 63303) > > > > The Git tag commons-dbutils-1.8.0-RC1 commit for this RC is > > 675cfcd2f68b03254746c24d76a83a23dcddc6a2 which you can browse here: > > > https://gitbox.apache.org/repos/asf?p=commons-dbutils.git;a=commit;h=675cfcd2f68b03254746c24d76a83a23dcddc6a2 > > You may checkout this tag using: > >git clone https://gitbox.apache.org/repos/asf/commons-dbutils.git > > --branch commons-dbutils-1.8.0-RC1 commons-dbutils-1.8.0-RC1 > > > > Maven artifacts are here: > > > https://repository.apache.org/content/repositories/orgapachecommons-1648/commons-dbutils/commons-dbutils/1.8.0/ > > > > These are the artifacts and their hashes: > > > > #Release SHA-512s > > #Tue Aug 01 20:32:34 EDT 2023 > > > commons-dbutils-1.8.0-src.tar.gz=be1af717639a605d9510e2ac7435c0f06ba37ce8700e93f38e3f71a83ea2758c71821545d7271adc5ae7d9506c1f557386ee9b67a4979f9ab3fe7cb27a08e179 > > > commons-dbutils_commons-dbutils-1.8.0.spdx.json=295f2decdbf6e68696b5c44939029deec01ae8619dae4093b617f4171968cf8b281bd723815331e124a807fb1c5e74b5c22cf6c146281857874f1be38ef12cde > > > commons-dbutils-1.8.0-sources.jar=6ab3192fb57bbdabfeb5f9992e3922cf7e6ef221d3ec5a7d66bd079406f6235058bfb6f115fa3e1ad7c8e02cd65fbb00adebf65c9c8914ba2758b30c24d97e32 > > > commons-dbutils-1.8.0-bom.json=6f939509e9cf901fab00c5e45e38ca8dcfe81c35069c97a270e0ba89f0d557feddd5f98b1320ed346e401e7be5a560325c021b6d8ba55ea2b0ea0a8652d037cb > > > commons-dbutils-1.8.0-test-sources.jar=dac78668a91c6d3eed45f591a8a2c83f3cfc4871bd3a478aa0ed117ad6b315f9e14c43e38aafcf8b6e4f2e4e8076802dc2481d3bc1950f2cb928e74685cee960 > > > commons-dbutils-1.8.0-src.zip=0af2de984787938c1277cf34a5e54cf50dd1674e962cc7280c47f6129ceeda86f8e18e422056dbf859f774cc65135e786552bb4847869e1f6e4c6f3bb089e9c7 > > > commons-dbutils-1.8.0-bom.xml=5d7be2ff22c55ce73022230a4f2242b9d43c9fe6dcf1cda552d19c4bcb255222adb78774bdfc57f0159da947ea65509fd63ad568c79f5fed51e4bb3a2ae8142b > > > commons-dbutils-1.8.0-bin.zip=76ebf30c465218022210f4e6ffc61756360a949156b5b3100ff9024ae6d782c328624b3bf1149280b0df4c466d3b4687efa92e6f9c483fc800bac47eddb0fbf5 > > > commons-dbutils-1.8.0-javadoc.jar=453cdd7517bc1f1ab0fb48e57d2795e8d1ded586246640a77b2b71d10c227ee7fae9c952f7cb82746be3df3e6544e097219873c732ba7b70271961666c2512bd > > > commons-dbutils-1.8.0-bin.tar.gz=1f3832fd5e7a997d93174b8c08f630522b7ef59b878e48ea1aa1f80924290dec6ce56db9ae003c010eec4384e8aea33d8c4b84e4d232bf7ba13ae42b3618e25f > > > commons-dbutils-1.8.0-tests.jar=96291ca4e46c5c426c45d65c4a219aeadb2f9fe1b4e18dd293d1a0529b171403a064a59f675707f2cf773a6a813abf8d1b58f3e46f9652a28eec4193d2421c97 > > > > I have tested this with > > > > mvn -V -Prelease -Ptest-deploy -P jacoco -P japicmp clean package site > deploy > > > > Using: > > > > Apache Maven 3.9.3 (21122926829f1ead511c958d89bd2f672198ae9f) > > Maven home: /usr/local/Cellar/maven/3.9.3/libexec > > Java version: 11.0.20, vendor: Homebrew, runtime: > > /usr/local/Cellar/openjdk@11/11.0.20/libexec/openjdk.jdk/Contents/Home > > Default locale: en_US, platform encoding: UTF-8 > > OS name: "mac os x", version: "13.5", arch: "x86_64", family: "mac" > > Darwin gdg-mac-mini.local 22.6.0 Darwin Kernel Version 22.6.0: Wed Jul > > 5 22:21:56 PDT 2023; root:xnu-8796.141.3~6/RELEASE_X86_64 x86_64 > > > > Java 11 is used to produce a JPMS module but the target byte code and > > API is enforced as Java 8. > > > > Details of changes since 1.7 are in the release notes: > > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/RELEASE-NOTES.txt > > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/changes-report.html > > > > Site: > > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/index.html > >(note some *relative* links are broken and the 1.8.0 directories > > are not yet created - these will be OK once the site is deployed.) > > > > JApiCmp Report (compared to 1.7): > > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/japicmp.html > > > > RAT Report: > > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/rat-report.html > > > > KEYS: > > https://downloads.apache.org/commons/KEYS > > > > Please review the release candidate and vote. > > This vote will close no sooner than 72 hours from now. > > > > [ ] +1 Release these artifacts > > [ ] +0 OK, but... > > [ ] -0 OK, but really should fix... > > [ ] -1 I oppose this release because... > > > > Thank you, > > > > Gary Gregory, > >
Re: [VOTE] Release Apache Commons DbUtils 1.8.0 based on RC1
All looks approriate signatures ok build ok on java 8, 11, 17 reports look good. Send it! +1 > On Aug 1, 2023, at 8:40 PM, Gary Gregory wrote: > > We have fixed a few bugs and added some enhancements since Apache > Commons DbUtils 1.7 was released, so I would like to release Apache > Commons DbUtils 1.8.0. > > Apache Commons DbUtils 1.8.0 RC1 is available for review here: >https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1 > (svn revision 63303) > > The Git tag commons-dbutils-1.8.0-RC1 commit for this RC is > 675cfcd2f68b03254746c24d76a83a23dcddc6a2 which you can browse here: > > https://gitbox.apache.org/repos/asf?p=commons-dbutils.git;a=commit;h=675cfcd2f68b03254746c24d76a83a23dcddc6a2 > You may checkout this tag using: >git clone https://gitbox.apache.org/repos/asf/commons-dbutils.git > --branch commons-dbutils-1.8.0-RC1 commons-dbutils-1.8.0-RC1 > > Maven artifacts are here: > > https://repository.apache.org/content/repositories/orgapachecommons-1648/commons-dbutils/commons-dbutils/1.8.0/ > > These are the artifacts and their hashes: > > #Release SHA-512s > #Tue Aug 01 20:32:34 EDT 2023 > commons-dbutils-1.8.0-src.tar.gz=be1af717639a605d9510e2ac7435c0f06ba37ce8700e93f38e3f71a83ea2758c71821545d7271adc5ae7d9506c1f557386ee9b67a4979f9ab3fe7cb27a08e179 > commons-dbutils_commons-dbutils-1.8.0.spdx.json=295f2decdbf6e68696b5c44939029deec01ae8619dae4093b617f4171968cf8b281bd723815331e124a807fb1c5e74b5c22cf6c146281857874f1be38ef12cde > commons-dbutils-1.8.0-sources.jar=6ab3192fb57bbdabfeb5f9992e3922cf7e6ef221d3ec5a7d66bd079406f6235058bfb6f115fa3e1ad7c8e02cd65fbb00adebf65c9c8914ba2758b30c24d97e32 > commons-dbutils-1.8.0-bom.json=6f939509e9cf901fab00c5e45e38ca8dcfe81c35069c97a270e0ba89f0d557feddd5f98b1320ed346e401e7be5a560325c021b6d8ba55ea2b0ea0a8652d037cb > commons-dbutils-1.8.0-test-sources.jar=dac78668a91c6d3eed45f591a8a2c83f3cfc4871bd3a478aa0ed117ad6b315f9e14c43e38aafcf8b6e4f2e4e8076802dc2481d3bc1950f2cb928e74685cee960 > commons-dbutils-1.8.0-src.zip=0af2de984787938c1277cf34a5e54cf50dd1674e962cc7280c47f6129ceeda86f8e18e422056dbf859f774cc65135e786552bb4847869e1f6e4c6f3bb089e9c7 > commons-dbutils-1.8.0-bom.xml=5d7be2ff22c55ce73022230a4f2242b9d43c9fe6dcf1cda552d19c4bcb255222adb78774bdfc57f0159da947ea65509fd63ad568c79f5fed51e4bb3a2ae8142b > commons-dbutils-1.8.0-bin.zip=76ebf30c465218022210f4e6ffc61756360a949156b5b3100ff9024ae6d782c328624b3bf1149280b0df4c466d3b4687efa92e6f9c483fc800bac47eddb0fbf5 > commons-dbutils-1.8.0-javadoc.jar=453cdd7517bc1f1ab0fb48e57d2795e8d1ded586246640a77b2b71d10c227ee7fae9c952f7cb82746be3df3e6544e097219873c732ba7b70271961666c2512bd > commons-dbutils-1.8.0-bin.tar.gz=1f3832fd5e7a997d93174b8c08f630522b7ef59b878e48ea1aa1f80924290dec6ce56db9ae003c010eec4384e8aea33d8c4b84e4d232bf7ba13ae42b3618e25f > commons-dbutils-1.8.0-tests.jar=96291ca4e46c5c426c45d65c4a219aeadb2f9fe1b4e18dd293d1a0529b171403a064a59f675707f2cf773a6a813abf8d1b58f3e46f9652a28eec4193d2421c97 > > I have tested this with > > mvn -V -Prelease -Ptest-deploy -P jacoco -P japicmp clean package site deploy > > Using: > > Apache Maven 3.9.3 (21122926829f1ead511c958d89bd2f672198ae9f) > Maven home: /usr/local/Cellar/maven/3.9.3/libexec > Java version: 11.0.20, vendor: Homebrew, runtime: > /usr/local/Cellar/openjdk@11/11.0.20/libexec/openjdk.jdk/Contents/Home > Default locale: en_US, platform encoding: UTF-8 > OS name: "mac os x", version: "13.5", arch: "x86_64", family: "mac" > Darwin gdg-mac-mini.local 22.6.0 Darwin Kernel Version 22.6.0: Wed Jul > 5 22:21:56 PDT 2023; root:xnu-8796.141.3~6/RELEASE_X86_64 x86_64 > > Java 11 is used to produce a JPMS module but the target byte code and > API is enforced as Java 8. > > Details of changes since 1.7 are in the release notes: > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/RELEASE-NOTES.txt > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/changes-report.html > > Site: > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/index.html >(note some *relative* links are broken and the 1.8.0 directories > are not yet created - these will be OK once the site is deployed.) > > JApiCmp Report (compared to 1.7): > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/japicmp.html > > RAT Report: > > https://dist.apache.org/repos/dist/dev/commons/dbutils/1.8.0-RC1/site/rat-report.html > > KEYS: > https://downloads.apache.org/commons/KEYS > > Please review the release candidate and vote. > This vote will close no sooner than 72 hours from now. > > [ ] +1 Release these artifacts > [ ] +0 OK, but... > [ ] -0 OK, but really should fix... > [ ] -1 I oppose this release because... > > Thank you, > > Gary Gregory, > Release Manager (using key 86fdc7e2a11262cb) > > For following is intended as a helper and refresher for reviewers. > > Validating a release candidate > == > > These guidelines are NOT complete. > >
Re: [commons-lang] Comments on new FunctionUtils / nested lambda feature
Worth adding adding function(Function)? Seems low cost to add it FailableFunction. Gary On Fri, Aug 4, 2023, 2:04 PM Rob Spoor wrote: > With just one simple utility method you can get all the chaining you want: > > public static Function function(Function func) { > return func; > } > > This doesn't look very useful, but it allows you to turn a method > reference or lambda into a typed Function without needing a cast. After > that it's really simple using what's provided in the Java API: > > Function func = function(MyBean::getChild) > .andThen(Child::getName); > > You want a default value? Almost just as easy: > > someFrameworkThing.setProperty(function(ParentBean::getChild) > .andThen(ChildBean::getName) > .andThen(Optional::ofNullable) > .andThen(o -> o.orElse("defaultName")); > > > On 04/08/2023 16:04, Daniel Watson wrote: > > Asking for comments and thoughts on a potential new feature. Already > > developed in a commons-like style, but dont want to submit PR without > > discussion as it may be considered out of scope or too use case specific. > > > > Justification and details... > > > > I've run into a scenario a few times where nested lamba functions would > be > > incredibly useful. e.g. > > > > MyBean::getChild::getName > > > > Obviously this is not a language feature, but can be simulated in a > useful > > way. So far my use has mostly been related to code that works with POJO > > beans, and frameworks that use function references to understand those > > beans and properties. Specifically useful where the context of the code > > block is the parent entity, but you need to reference a child, and > without > > nested lambdas you end up with things like the below... > > > > ParentBean parentBean = new ParentBean(); > > parentBean.setChild(new ChildBean("name")); > > //imagine that FrameworkThing is a generic class, and thus the generic > type > > is ParentBean > > FrameworkThing someFrameworkThing = new FrameworkThing (ParentBean.class) > > //but we need to get to a property of a child bean > > someFrameworkThing.setProperty((parentBean) -> { > > > > return parentBean.getChild().getName(); > > > > }); > > > > Obviously this could be handled with a getChildName() method on the > parent > > bean, but that has pitfalls as well (e.g. bean class cannot be changed, > or > > adding of properties interferes with other usage of the class e.g. JPA, > > JAX). However with a util class the second call can be reduced to > > something like below, leaving the bean API untouched. > > > > > someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName)); > > > > Taken alone, that single reduction may seem trivial, but in a scenario > > where these nested references are commonly needed, the reduction makes > the > > code clearer (In my opinion), as it is immediately apparent on a single > > line of code that the reference is a simple nested property, rather than > > having to interpret an inline lambda function. It also discourages errant > > placement of code by avoiding the inline function (since the only purpose > > of the lambda was to retrieve a single nested value). In addition, If > > intermediate nulls need to be handled then the reduction becomes more > > apparent, as the null checks can be handled in the util class rather than > > cluttering the app code. e.g. > > > > > someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,"defaultName")); > > //or... > > > someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,null)); > > > > The third parameter here is a String (typed genetically based on the > return > > type of getName) and indicates the default value to be returned if the > > first call to getChild() returns null. e.g. it replaces something like... > > > > someFrameworkThing.setProperty((parentBean) -> { > > > > ChildBean cb = parentBean.getChild(); > > if(cb == null) return null; //or other default value > > else return cb.getName(); > > > > }); > > > > Given that commons-lang aims to extend existing language features, this > > seemed like a reasonable place for a nested lambda util class. So far my > > concerns are... > > > > 1. Does this feel too specific to an application to warrant > inclusion in > > commons? (For me it has been useful enough to place into a common > library, > > but commons-lang has a broader scope) > > 2. If not commons-lang, is there some other commons library that > this is > > more suited to? > > 3. There are still wrinkles that may prove complex and potentially > > overly specific e.g. exception handling. Does that potential > complexity > > make it not worth adding? > > 4. Assuming the features discussed here *are* valuable, Is handling > only > > java.util.Function a complete-enough feature? Or is it useless > unless it > > also attempts to
Re: [commons-lang] Comments on new FunctionUtils / nested lambda feature
Appreciate the feedback. That's a great point. I missed the potential of the andThen(...) method. One minor thing to point out - My proposed purpose of the default value parameter was not to substitute the final value if it is null, but to substitute the final value if it cannot be obtained, due the *parent* being null. So in my example, it is the return value of getChild() that would be null, and your code would fail with a NPE. To handle this using the chaining approach I think would look something like: function(ParentBean::getChild) .andThen(Optional::ofNullable) .andThen(o -> { return o.map(ChildBean::getName).orElse("defaultName"); }); So overall it's similar to yours, you just need the .map() call to change the optional type to match the final return type. That probably covers a lot of scenarios, however I still consider it a bit tedious, and it becomes even more tedious if we nest it one level further because the handling of null is now always an inline function. (I realize that level of nesting might be rare. I personally have needed it, but I understand that alone is not justification enough) For my usage of it, It's still much clearer to see a util method call, with method references, rather than chaining via andThen, because most uses need to handle null, which means I'd still be stuck with inline functions everywhere. In the end the biggest benefit of the util call is the clarity of quickly knowing that the purpose is to retrieve a simple nested property, which I don't think you can realistically get when having to decipher a chain of functions and optionals. Dan On Fri, Aug 4, 2023 at 2:04 PM Rob Spoor wrote: > With just one simple utility method you can get all the chaining you want: > > public static Function function(Function func) { > return func; > } > > This doesn't look very useful, but it allows you to turn a method > reference or lambda into a typed Function without needing a cast. After > that it's really simple using what's provided in the Java API: > > Function func = function(MyBean::getChild) > .andThen(Child::getName); > > You want a default value? Almost just as easy: > > someFrameworkThing.setProperty(function(ParentBean::getChild) > .andThen(ChildBean::getName) > .andThen(Optional::ofNullable) > .andThen(o -> o.orElse("defaultName")); > > > On 04/08/2023 16:04, Daniel Watson wrote: > > Asking for comments and thoughts on a potential new feature. Already > > developed in a commons-like style, but dont want to submit PR without > > discussion as it may be considered out of scope or too use case specific. > > > > Justification and details... > > > > I've run into a scenario a few times where nested lamba functions would > be > > incredibly useful. e.g. > > > > MyBean::getChild::getName > > > > Obviously this is not a language feature, but can be simulated in a > useful > > way. So far my use has mostly been related to code that works with POJO > > beans, and frameworks that use function references to understand those > > beans and properties. Specifically useful where the context of the code > > block is the parent entity, but you need to reference a child, and > without > > nested lambdas you end up with things like the below... > > > > ParentBean parentBean = new ParentBean(); > > parentBean.setChild(new ChildBean("name")); > > //imagine that FrameworkThing is a generic class, and thus the generic > type > > is ParentBean > > FrameworkThing someFrameworkThing = new FrameworkThing (ParentBean.class) > > //but we need to get to a property of a child bean > > someFrameworkThing.setProperty((parentBean) -> { > > > > return parentBean.getChild().getName(); > > > > }); > > > > Obviously this could be handled with a getChildName() method on the > parent > > bean, but that has pitfalls as well (e.g. bean class cannot be changed, > or > > adding of properties interferes with other usage of the class e.g. JPA, > > JAX). However with a util class the second call can be reduced to > > something like below, leaving the bean API untouched. > > > > > someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName)); > > > > Taken alone, that single reduction may seem trivial, but in a scenario > > where these nested references are commonly needed, the reduction makes > the > > code clearer (In my opinion), as it is immediately apparent on a single > > line of code that the reference is a simple nested property, rather than > > having to interpret an inline lambda function. It also discourages errant > > placement of code by avoiding the inline function (since the only purpose > > of the lambda was to retrieve a single nested value). In addition, If > > intermediate nulls need to be handled then the reduction becomes more > > apparent, as the null checks can be handled in the util class rather than > > cluttering the app code. e.g. > > > > >
Re: [commons-lang] Comments on new FunctionUtils / nested lambda feature
With just one simple utility method you can get all the chaining you want: public static Function function(Function func) { return func; } This doesn't look very useful, but it allows you to turn a method reference or lambda into a typed Function without needing a cast. After that it's really simple using what's provided in the Java API: Function func = function(MyBean::getChild) .andThen(Child::getName); You want a default value? Almost just as easy: someFrameworkThing.setProperty(function(ParentBean::getChild) .andThen(ChildBean::getName) .andThen(Optional::ofNullable) .andThen(o -> o.orElse("defaultName")); On 04/08/2023 16:04, Daniel Watson wrote: Asking for comments and thoughts on a potential new feature. Already developed in a commons-like style, but dont want to submit PR without discussion as it may be considered out of scope or too use case specific. Justification and details... I've run into a scenario a few times where nested lamba functions would be incredibly useful. e.g. MyBean::getChild::getName Obviously this is not a language feature, but can be simulated in a useful way. So far my use has mostly been related to code that works with POJO beans, and frameworks that use function references to understand those beans and properties. Specifically useful where the context of the code block is the parent entity, but you need to reference a child, and without nested lambdas you end up with things like the below... ParentBean parentBean = new ParentBean(); parentBean.setChild(new ChildBean("name")); //imagine that FrameworkThing is a generic class, and thus the generic type is ParentBean FrameworkThing someFrameworkThing = new FrameworkThing (ParentBean.class) //but we need to get to a property of a child bean someFrameworkThing.setProperty((parentBean) -> { return parentBean.getChild().getName(); }); Obviously this could be handled with a getChildName() method on the parent bean, but that has pitfalls as well (e.g. bean class cannot be changed, or adding of properties interferes with other usage of the class e.g. JPA, JAX). However with a util class the second call can be reduced to something like below, leaving the bean API untouched. someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName)); Taken alone, that single reduction may seem trivial, but in a scenario where these nested references are commonly needed, the reduction makes the code clearer (In my opinion), as it is immediately apparent on a single line of code that the reference is a simple nested property, rather than having to interpret an inline lambda function. It also discourages errant placement of code by avoiding the inline function (since the only purpose of the lambda was to retrieve a single nested value). In addition, If intermediate nulls need to be handled then the reduction becomes more apparent, as the null checks can be handled in the util class rather than cluttering the app code. e.g. someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,"defaultName")); //or... someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,null)); The third parameter here is a String (typed genetically based on the return type of getName) and indicates the default value to be returned if the first call to getChild() returns null. e.g. it replaces something like... someFrameworkThing.setProperty((parentBean) -> { ChildBean cb = parentBean.getChild(); if(cb == null) return null; //or other default value else return cb.getName(); }); Given that commons-lang aims to extend existing language features, this seemed like a reasonable place for a nested lambda util class. So far my concerns are... 1. Does this feel too specific to an application to warrant inclusion in commons? (For me it has been useful enough to place into a common library, but commons-lang has a broader scope) 2. If not commons-lang, is there some other commons library that this is more suited to? 3. There are still wrinkles that may prove complex and potentially overly specific e.g. exception handling. Does that potential complexity make it not worth adding? 4. Assuming the features discussed here *are* valuable, Is handling only java.util.Function a complete-enough feature? Or is it useless unless it also attempts to handle BiFunctions - which become increasingly complex (potentially unfeasible) to implement - i.e. is it too big a feature to consider including? If folks feel like this is a solid "no" let me know. If the devil is in the details and we need to see the PR first I can do that as well. Dan - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
[commons-lang] Comments on new FunctionUtils / nested lambda feature
Asking for comments and thoughts on a potential new feature. Already developed in a commons-like style, but dont want to submit PR without discussion as it may be considered out of scope or too use case specific. Justification and details... I've run into a scenario a few times where nested lamba functions would be incredibly useful. e.g. MyBean::getChild::getName Obviously this is not a language feature, but can be simulated in a useful way. So far my use has mostly been related to code that works with POJO beans, and frameworks that use function references to understand those beans and properties. Specifically useful where the context of the code block is the parent entity, but you need to reference a child, and without nested lambdas you end up with things like the below... ParentBean parentBean = new ParentBean(); parentBean.setChild(new ChildBean("name")); //imagine that FrameworkThing is a generic class, and thus the generic type is ParentBean FrameworkThing someFrameworkThing = new FrameworkThing (ParentBean.class) //but we need to get to a property of a child bean someFrameworkThing.setProperty((parentBean) -> { return parentBean.getChild().getName(); }); Obviously this could be handled with a getChildName() method on the parent bean, but that has pitfalls as well (e.g. bean class cannot be changed, or adding of properties interferes with other usage of the class e.g. JPA, JAX). However with a util class the second call can be reduced to something like below, leaving the bean API untouched. someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName)); Taken alone, that single reduction may seem trivial, but in a scenario where these nested references are commonly needed, the reduction makes the code clearer (In my opinion), as it is immediately apparent on a single line of code that the reference is a simple nested property, rather than having to interpret an inline lambda function. It also discourages errant placement of code by avoiding the inline function (since the only purpose of the lambda was to retrieve a single nested value). In addition, If intermediate nulls need to be handled then the reduction becomes more apparent, as the null checks can be handled in the util class rather than cluttering the app code. e.g. someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,"defaultName")); //or... someFrameworkThing.setProperty(FunctionUtils.nested(ParentBean::getChild,ChildBean::getName,null)); The third parameter here is a String (typed genetically based on the return type of getName) and indicates the default value to be returned if the first call to getChild() returns null. e.g. it replaces something like... someFrameworkThing.setProperty((parentBean) -> { ChildBean cb = parentBean.getChild(); if(cb == null) return null; //or other default value else return cb.getName(); }); Given that commons-lang aims to extend existing language features, this seemed like a reasonable place for a nested lambda util class. So far my concerns are... 1. Does this feel too specific to an application to warrant inclusion in commons? (For me it has been useful enough to place into a common library, but commons-lang has a broader scope) 2. If not commons-lang, is there some other commons library that this is more suited to? 3. There are still wrinkles that may prove complex and potentially overly specific e.g. exception handling. Does that potential complexity make it not worth adding? 4. Assuming the features discussed here *are* valuable, Is handling only java.util.Function a complete-enough feature? Or is it useless unless it also attempts to handle BiFunctions - which become increasingly complex (potentially unfeasible) to implement - i.e. is it too big a feature to consider including? If folks feel like this is a solid "no" let me know. If the devil is in the details and we need to see the PR first I can do that as well. Dan