Yep that's correct. You cant get strong typing with varargs. Overloading (yes, lazy) is how I handle it right now. I believe there's really one 2 methods that do anything significant to accomplish the goal, one that calls a single nested function, and one that calls a single nested BiConsumer. The rest essentially just chain on top of those.
More thought could certainly be given to it. There may be other related use cases I haven't encountered. And I've yet to need nesting beyond 3 levels, but would probaby offer methods that go a few levels beyond that, if only because the cost is very little. On Sun, Aug 6, 2023, 5:49 AM Rob Spoor <apa...@icemanx.nl> wrote: > I don't think that function chaining with varargs works, except with > UnaryOperator. After all, the output type of the first must be > compatible with the input type of the second, the output type of the > second must be compatible with the input type of the third, etc. > > If you want to continue this way, the best option would be to have some > overloads: > > <T, I, R> Function<T, R> nested( > Function<? super T, ? extends I> first, > Function<? super I, ? extends R> second) > <T, I, R> Function<T, R> nested( > Function<? super T, ? extends I> first, > Function<? super I, ? extends R> second, > R defaultValue) > <T, I1, I2, R> Function<T, R> nested( > Function<? super T, ? extends I1> first, > Function<? super I1, ? extends I2> second, > Function<? super I2, ? extends R> third) > <T, I1, I2, R> Function<T, R> nested( > Function<? super T, ? extends I1> first, > Function<? super I1, ? extends I2> second, > Function<? super I2, ? extends R> third, > R defaultValue) > ... > > If you're lazy you can delegate the overload with N functions to the > overload with N-1 functions: > > <T, I1, I2, I3, R> Function<T, R> nested( > Function<? super T, ? extends I1> first, > Function<? super I1, ? extends I2> second, > Function<? super I2, ? extends I3> third, > Function<? super I3, ? extends R> fourth, > R defaultValue) { > > return nested(first, nested(second, third, fourth), > defaultValue); > } > > > Rob > > > On 06/08/2023 01:28, Gary Gregory wrote: > > I'm not sure the "nested" example API is quite what it should be, because > > the last argument is the default value, you cannot make the input > functions > > a vararg, which seems very limiting. I should be able to use the same API > > whether I need to go 1, 2, or N functions deep. I'm saying the above > > independently of whether this type of code should be in Lang. > > > > Gary > > > > On Sat, Aug 5, 2023, 9:27 AM Daniel Watson <dcwatso...@gmail.com> wrote: > > > >> Nice. > >> > >> Sounds like everyone is leaning towards "no". Would it be worth > submitting > >> a PR to include more usage examples - which I assume could also serve > as a > >> place to collect more feedback? Or just keep it within this thread given > >> the way it's leaning? (or unless that consensus changes) > >> > >> Ultimately in my web/UI project the reduction (after using > function(...)) > >> is something like... > >> > >> Failable.asFunction(Parent::getChild) > >> .andThen(Optional::ofNullable) > >> .andThen(o -> o.map(Child::getGrandChild)) > >> .andThen(o-> o.map(GrandChild::getName).orElse(defaultValue)); > >> > >> vs my util method > >> > >> FunctionUtils.nested(Parent::getChild, Child::getGrandChild, > >> GrandChild::getName, defaultValue); > >> > >> So it's still a big difference in clarity for me, given how often its > used. > >> FWIW - My project is using Vaadin, and this util function is used to > bind > >> nested bean properties to Vaadin input fields. On that note - In > addition > >> to the bean "getter" binding, it also uses a similar util method to bind > >> bean "setter" methods - because input fields obviously need access to > both. > >> The setter util call looks similar, with the last argument being > >> a BiConsumer... > >> > >> FunctionUtils.nested(Parent::getChild, Child::getGrandChild, > >> GrandChild::setName); > >> > >> Although in general this code does not reference any Vaadin specific > >> functionality, the overall use case may be quite specific to those > needs, > >> so all of these utilities may be better suited to a utils class within a > >> vaadin specific library. > >> > >> Dan > >> > >> On Fri, Aug 4, 2023 at 9:11 PM Gary Gregory <garydgreg...@gmail.com> > >> wrote: > >> > >>> 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 <garydgreg...@gmail.com> > >> wrote: > >>> > >>>> Worth adding adding function(Function)? Seems low cost to add it > >>>> FailableFunction. > >>>> > >>>> Gary > >>>> > >>>> On Fri, Aug 4, 2023, 2:04 PM Rob Spoor <apa...@icemanx.nl> wrote: > >>>> > >>>>> With just one simple utility method you can get all the chaining you > >>> want: > >>>>> > >>>>> public static <T, R> Function<T, R> function(Function<T, R> > >> 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<MyBean, String> 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 > >>>>> > >>>>> > >>> > >> > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > >