Re: "Fat-free Lambdas"
Jochen Theodorou <[email protected]> Sat, 23 May 2026 16:46:34 +0200
| Newsgroups | gmane.comp.lang.groovy.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Paul,
I think we have to separate memory consumption and performance a bit
here. Of course allocating in a loop costs performance compared to not
allocating. Creating new objects is not exactly cheap on the JVM, so
here the two touch for this case.
For example the case of performance cost for CurriedClosure. Yes, we
rewrap the array and thus we create a ton of useless Objects. But do we
really have to? I think not. Nothing except manpower, time and
motivation stops us from collapsing CurriedClosures. This can partially
happen at construction time, partially this can happen at the callsite
itself. And interestingly, we probably could even save on some guards..
Actually there is some space for optimization in general. But this does
not solve the problem of if you create the CurriedClosure inside the hot
loop. Then you still carry the cost of creating lots of CurriedClosure
objects.
Quite some time ago I was toying with the idea of having a special
non-capturing Closure, that is incompatible with the capturing Closure.
Why? then for example a builder can make it clear by signature that it
will require a delegate, or something like findAll can make it clear,
that there will be no use of delegation. Well, that was an idea, did not
get very far with it. I feel there is quite a bit optimization potential
here as well - similar to non capturing lambdas. But if you then go and
pack everything in a Closure as it is today, it won't got far I think.
Which is also why this works with lambdas in static compilation, but not
in dynamic Groovy... unless we fundamentally change the way these things
are done. For example in "words.findAll(String::startsWith, 'A')", we
could in theory just have a reusable wrapper for a MethodHandle, even
create the wrapper at the callsite only (and keep it there) to tailor it
to what we require for the method we call it with... hmm... that is
similar to what is done for lambdas I think... just not as dynamic.
Then there is the aspect of "looks". findAll with 2 parameters looks a
bit odd on first look. But maybe that is something getting used too?
bye Jochen
On 5/23/26 14:53, Paul King wrote:
> Hi folks,
>
> Donald Raab of Eclipse Collections fame, did a recent blog post about
> what that library has done for better performance:
>
> https://donraab.medium.com/fat-free-lambdas-in-java-bf228da0613b
>
> Donald sent me a private message asking about Groovy's take on some of
> those optimisations, so I thought it might be interesting to analyse
> things. Past optimisation work, and the recent work Daniel did on
> optimizing non-capturing lambdas put Groovy on a good footing for some
> metrics but for many of our DGM methods that take Closures, we have
> ways (with varying degrees of impact) to make things more performant.
>
> I did a benchmark and the results are in:
>
> https://issues.apache.org/jira/browse/GROOVY-12034
>
> There is a PR but currently the PR is just the benchmark tests
> themselves, not any code changes at present:
>
> https://github.com/apache/groovy/pull/2557
>
> I'd encourage folks to read that ticket, we have a few options we
> might want to explore.
>
> TL;DR
> * there are a few potential optimsations we might be able to apply for
> existing code
> * we might want to consider a curryWith method, kind of a lazy rcurry
> * we might want to consider the equivalent of Eclipse Collections
> "*With" method variants. Instead of "words.findAll{ it.startsWith('A')
> }" we'd have a variant "words.findAll(String::startsWith, 'A')
>
> Anyway, I'll ponder things a bit more and make some follow-up
> PRs/emails. The analysis suggests just creating the extra variants on
> a handful of the most widely used DGM methods. But feedback is most
> welcome.
>
> Cheers, Paul.