<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div dir="ltr"></div><div dir="ltr">The generator is closed in response to yield() - this could have been an exception as well. It is also “closed” if it returns for any reason including an exception. It is all built into the framework - the dev does not need to code anything special. </div><div dir="ltr"><br></div><div dir="ltr">The code is less than 150 lines for the complete generic implementation. The code to write and use a generator can be a single line. How much simpler do you need?</div><div dir="ltr"><br><blockquote type="cite">On Jul 5, 2023, at 6:57 AM, Alex Otenko <oleksandr.otenko@gmail.com> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="auto"><div>Well, the code you shared only illustrates that it is not as simple as claimed.<div dir="auto"><br></div><div dir="auto">So, you don't use a queue. That's fine. Now, how will the generator stop? You have the close() in finalize(), and a dance around hasNext() to totally order the delivery of elements vs end of stream.</div><div dir="auto"><br></div><div dir="auto">Basically, it's two channels.</div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 4 Jul 2023, 15:07 robert engels, <<a href="mailto:rengels@ix.netcom.com">rengels@ix.netcom.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">It is also straightforward to use a buffered queue to allow the producer to read ahead rather than the hand-off queue as implemented - which is often necessary when the producer is reading from a database, network calls, etc.<div><br></div><div>There is no need to for specific generator support in Java when you have cheap virtual threads.<br><div><br><blockquote type="cite"><div>On Jul 4, 2023, at 8:58 AM, robert engels <<a href="mailto:rengels@ix.netcom.com" target="_blank" rel="noreferrer">rengels@ix.netcom.com</a>> wrote:</div><br><div><div style="word-wrap:break-word;line-break:after-white-space">I created a project to demonstrate. It uses finalizers for simplicity but it easily adaptable to weak reference queues. It only needs a single producer virtual thread per generator.<div><br></div><div>see <a href="https://github.com/robaho/generators/tree/main" target="_blank" rel="noreferrer">https://github.com/robaho/generators/tree/main</a><br><div><br><blockquote type="cite"><div>On Jul 4, 2023, at 7:24 AM, Robert Engels <<a href="mailto:rengels@ix.netcom.com" target="_blank" rel="noreferrer">rengels@ix.netcom.com</a>> wrote:</div><br><div><div dir="auto"><div dir="ltr"></div><div dir="ltr">You need 3 threads - the producer the consumer and the watcher (the watcher and producer might be able to be combined with async notifications from the weak reference queue) But it is all encapsulated and virtual threads makes this very cheap - as cheap as actual continuations would be. </div><div dir="ltr"><br><blockquote type="cite">On Jul 4, 2023, at 7:19 AM, Alex Otenko <<a href="mailto:oleksandr.otenko@gmail.com" target="_blank" rel="noreferrer">oleksandr.otenko@gmail.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="auto">So it's not really just the queue.<div dir="auto"><br></div><div dir="auto">Plus you need two of them. Otherwise you can't control the timing of when the next value is produced.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 4 Jul 2023, 13:13 Robert Engels, <<a href="mailto:rengels@ix.netcom.com" target="_blank" rel="noreferrer">rengels@ix.netcom.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div dir="ltr"></div><div dir="ltr">To elaborate - the producer knows when no more values are coming and marks the iterator as such. So the next calls to hasNext()/next() fail appropriately. That is trivial. </div><div dir="ltr"><br></div><div dir="ltr">The only “complex” part of the design is that the returned iterator is tracked with a weak reference by the producer. So if it goes out of scope the producer can be woken from the blocked/waiting state and clean up. </div><div dir="ltr"><br><blockquote type="cite">On Jul 4, 2023, at 7:01 AM, Robert Engels <<a href="mailto:rengels@ix.netcom.com" rel="noreferrer noreferrer" target="_blank">rengels@ix.netcom.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"></div><div dir="ltr">That is built into the Iterator interface. </div><div dir="ltr"><br><blockquote type="cite">On Jul 4, 2023, at 4:05 AM, Alex Otenko <<a href="mailto:oleksandr.otenko@gmail.com" rel="noreferrer noreferrer" target="_blank">oleksandr.otenko@gmail.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="auto">How does the generator tell the consumer that no more values are forthcoming? </div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, 3 Jul 2023, 12:38 Robert Engels, <<a href="mailto:rengels@ix.netcom.com" rel="noreferrer noreferrer" target="_blank">rengels@ix.netcom.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div dir="ltr"></div><div dir="ltr">Believe me. Queues are all you need there is no memory leak and no need to “close”. The producer side uses a weak reference to the queue. When there are no more strong references the producer side can terminate. </div><div dir="ltr"><br></div><div dir="ltr">You can’t use a standard blocking queue for this - but the queue implementation is fairly trivial - with a wake-up thread that listens on the weak reference queue. </div><div dir="ltr"><br><blockquote type="cite">On Jul 3, 2023, at 6:19 AM, Attila Kelemen <<a href="mailto:attila.kelemen85@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">attila.kelemen85@gmail.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
2. We need to synchronize access to mutable state to avoid memory<br>
   hazards. This is a separate issue from synchronizing access to<br>
   mutable state to avoid correctness issues. With virtual threads on<br>
   a single platform thread, this goes away too (because it's always<br>
   the same thread observing memory operations; no barriers needed).<br><br></blockquote><div><br></div><div>That still seems incorrect to me (in principle, in practice it most likely will end up to be fine, but I just wouldn't rely on it), because the barrier is needed to prevent instruction reordering by the compiler, and you are not safe from that by using the same platform thread.</div></div></div>
</div></blockquote></div></blockquote></div>
</div></blockquote></div></blockquote></div></blockquote></div>
</div></blockquote></div></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div></blockquote></div></div></div>
</div></blockquote></body></html>