Gatherers -- conditionalWindowFixed?

David Alayachew davidalayachew at gmail.com
Sun Aug 4 07:15:59 UTC 2024


Hello,

Sorry I didn't respond when I said I was going to. I have been juggling
some pretty severe personal emergencies. So, not only am I overdue on this,
but I don't really have the energy to make the full post I originally
wanted to.

Regardless, I have made a new thread posting my findings, and why I think
this new windowBy function makes sense. Here is the link --
https://mail.openjdk.org/pipermail/core-libs-dev/2024-August/127293.html

Thank you for your time and patience!
David Alayachew

On Sun, Jan 28, 2024 at 1:54 AM David Alayachew <davidalayachew at gmail.com>
wrote:

> Thank you both for your replies!
>
> And thanks for the Gatherer example Viktor.
>
> It sounds like, from your email, that you want to see just how useful this
> method would be to add before we can justify adding it to Gatherers.
>
> Fair enough. I have spent a couple of days using this custom Gatherer you
> made for me, and I will post a new email thread either tomorrow or the day
> after that shows my experience with it. My hope is that I can convince you
> that this function absolutely is worth adding.
>
> Thank you for your time and help!
> David Alayachew
>
> On Wed, Jan 10, 2024 at 2:29 PM Viktor Klang <viktor.klang at oracle.com>
> wrote:
>
>> >1/ Is there a reason why the integrator is not declared greedy (I'm
>> still not sure to what exactly Greedy means in the context of gatherers) ?
>>
>> No, that was just a (benign) omission from typing the solution as I was
>> typing the email 🙂
>>
>> >2/ Is there a reason to write the code in a OOP way like you have done
>> instead of only having fields in State and specify the behaviors using
>> lambdas (because with lambdas will you get inference)
>>
>> Great question!
>> I chose to do that since I wanted to A) allocate the backing list
>> on-demand, and also B) not allocate a new ArrayList for the downstream
>> windows and retain the (cleared) old one (since its size could become
>> needlessly large).
>>
>>
>> As a side-note, I tend to prototype using lambdas and then refactor
>> as/when needed to either embed logic in the state or even migrate into a
>> full-on implementation of the Gatherer interface (for instance if I want to
>> override composition).
>>
>> Cheers,
>>>>
>>
>> *Viktor Klang*
>> Software Architect, Java Platform Group
>> Oracle
>>
>>
>> ------------------------------
>> *From:* Remi Forax <forax at univ-mlv.fr>
>> *Sent:* Wednesday, 10 January 2024 19:16
>> *To:* Viktor Klang <viktor.klang at oracle.com>
>> *Cc:* David Alayachew <davidalayachew at gmail.com>; core-libs-dev <
>> core-libs-dev at openjdk.org>
>> *Subject:* [External] : Re: Gatherers -- conditionalWindowFixed?
>>
>>
>>
>> ------------------------------
>>
>> *From: *"Viktor Klang" <viktor.klang at oracle.com>
>> *To: *"David Alayachew" <davidalayachew at gmail.com>, "core-libs-dev" <
>> core-libs-dev at openjdk.org>
>> *Sent: *Wednesday, January 10, 2024 2:33:45 PM
>> *Subject: *Re: Gatherers -- conditionalWindowFixed?
>>
>> Hi David!
>>
>> Apologies for the late reply, there's been lots of catching up to do
>> after the holidays.
>>
>> >I'm really excited for what this will enable for us.
>>
>> I'm really glad to hear that \uD83D\uDE42
>>
>> >It is very much appreciated.
>>
>> \uD83D\uDC4D
>>
>> > Could we add one more method for a conditionalWindowFixed? We would
>> need to pass in some Predicate<T>. If the predicate returns true, create a
>> list (if it does not already exist) then add the element to it. If the
>> predicate returns false while the list is empty, then just move along to
>> the next. Else if the predicate returns false while the list is non empty,
>> pass the list down into the stream. So, you end up with Stream<T> ----->
>> Stream<List<T>>.
>>
>> What ends up under Gatherers.* does require careful triaging, ideally by
>> first seeing user-created implementations being heavily used/useful, then
>> potential candidate for Gatherers.*, and then at the end it might end up in
>> Stream as a dedicated method.
>>
>> By virtue of the Gatherers API, it seems pretty straight-forward for you
>> to implement what you describe, and personally I'd probably call it
>> something like *windowBy*.
>>
>> Just typing this up as I write this reply, it could look something like
>> this:
>>
>> <TR> Gatherer<TR, ?, List<TR>> windowBy(Predicate<TR>
>> includeInCurrentWindow) {
>>   class State {
>>     ArrayList<TR> window;
>>
>>     boolean integrate(TR element, Gatherer.Downstream<? super List<TR>>
>> downstream) {
>>       if (window != null && !includeInCurrentWindow.test(element)) {
>>         var result = Collections.unmodifiableList(window);
>>         window = null;
>>         if (!downstream.push(result))
>>           return false;
>>       }
>>
>>       if (window == null)
>>         window = new ArrayList<>();
>>
>>       return window.add(element);
>>     }
>>
>>     void finish(Gatherer.Downstream<? super List<TR>> downstream) {
>>       if (window != null) {
>>         var result = Collections.unmodifiableList(window);
>>         window = null;
>>         downstream.push(result);
>>       }
>>     }
>>   }
>>   return Gatherer.<TR, State, List<TR>>ofSequential(State::new,
>> State::integrate, State::finish);
>> }
>>
>> jshell> Stream.of("header", "value1", "value2", "header", "header",
>> "value 3", "value 4",
>> null).gather(windowBy(Predicate.not("header"::equals))).toList()
>> $1 ==> [[header, value1, value2], [header], [header, value 3, value 4,
>> null]]
>>
>>
>> Hello,
>> I've two questions,
>> 1/ Is there a reason why the integrator is not declared greedy (I'm still
>> not sure to what exactly Greedy means in the context of gatherers) ?
>> 2/ Is there a reason to write the code in a OOP way like you have done
>> instead of only having fields in State and specify the behaviors using
>> lambdas (because with lambdas will you get inference)
>>
>> <T> Gatherer<T, ?, List<T>> windowBy(Predicate<? super T>
>> includeInCurrentWindow) {
>>   class State {
>>     ArrayList<T> window;
>>   }
>>   return Gatherer.ofSequential(
>>       State::new,
>>       (state, element, downstream) -> {
>>        ...
>>       },
>>       (state, downstream) -> {
>>         ...
>>       });
>> }
>>
>>
>> Cheers,
>>>>
>>
>> regards,
>> Rémi
>>
>>
>>
>> *Viktor Klang*
>> Software Architect, Java Platform Group
>> Oracle
>> ------------------------------
>> *From:* core-libs-dev <core-libs-dev-retn at openjdk.org> on behalf of
>> David Alayachew <davidalayachew at gmail.com>
>> *Sent:* Wednesday, 10 January 2024 07:05
>> *To:* core-libs-dev at openjdk.org <core-libs-dev at openjdk.org>
>> *Subject:* Gatherers -- conditionalWindowFixed?
>>
>> Hello Core Libs Dev Team,
>>
>> I have been reading through JEP 461 (https://openjdk.org/jeps/461) about
>> Gatherers, and I'm really excited for what this will enable for us.
>>
>> By far, the most important functionality that this API facilitates is the
>> ability to create windows. Anytime I needed a window, I was basically
>> forced to use a for loop. Now, the 2 most common window cases are being
>> handed to us for free. It is very much appreciated.
>>
>> Could we add one more method for a conditionalWindowFixed? We would need
>> to pass in some Predicate<T>. If the predicate returns true, create a list
>> (if it does not already exist) then add the element to it. If the predicate
>> returns false while the list is empty, then just move along to the next.
>> Else if the predicate returns false while the list is non empty, pass the
>> list down into the stream. So, you end up with Stream<T> ----->
>> Stream<List<T>>.
>>
>> The reason I think this is worth adding is because it facilitates a
>> really common use case. We may not want all windows to be the same size.
>>
>> Is this something worth adding to the Gatherers API?
>>
>> Thank you for your time and help!
>> David Alayachew
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240804/ed3c89f8/attachment-0001.htm>


More information about the core-libs-dev mailing list