Blocking stub should not return Iterator but Iterable/Collection (when proto method return stream)

622 views
Skip to first unread message

Martin Grześlowski

unread,
May 12, 2015, 7:39:25 AM5/12/15
to grp...@googlegroups.com
When proto-rpc-method return stream of objects in Java this is change to method Iterator<ProtoResponse> didIHeardItCorrect(ProtoRequest request). Using bare Iterator is pretty annoing (compared to Iterable or Collection), i.e. look at this snippet:

Iterator<HelloResponse> responseIterator = blockingStub.hello(helloRequest);
while (responseIterator.hasNext()) {
    doStuff(responseIterator.next());
}

Iterable<HelloResponse> responseIterable = blockingStub.hello(helloRequest);
for (HelloResponse response : responseIterable) {
    doStuff(response);
}

Definitly using Iterable is more idiomatic for Java. Implementing this also should not be rocket science. Internally iterator returned by gRPC is BlockingQueue which implements Queue->Collection->Iterable.

Only con against Iterable could be that you can invoke iterator() many times.

Josh Humphries

unread,
May 12, 2015, 9:31:37 AM5/12/15
to Martin Grześlowski, grpc-io
Only con against Iterable could be that you can invoke iterator() many times.

I think this is in fact the entire reason that it returns Iterator instead of Iterable. The stream can't be iterated more than once, so Iterator is the correct representation.

It cannot implement Collection because the actual number of elements is not known up-front (Collection provides a size() method that could not be implemented). Clients and servers just stream messages until they are done without having to report the number at the start of the operation.

If you need to adapt to Iterable, you could do use a lambda like () -> iterator. But if iterator() is invoked multiple times, it will always return the same object. So you could get interference between two pieces of code trying to iterator over the messages.

Iterable is only idiomatic for cases where you can iterate the sequence ad-hoc/repeatedly. But that does not apply here.

BTW, I don't see anything wrong in your code snippet. In fact, the Iterator sample is more concise and just as readable.

--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/b87ca627-c279-408f-9c4f-a7ffb7c55bf5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Martin Grześlowski

unread,
May 12, 2015, 10:19:22 AM5/12/15
to grp...@googlegroups.com, martin.gr...@gmail.com
Only con against Iterable could be that you can invoke iterator() many times.

I think this is in fact the entire reason that it returns Iterator instead of Iterable. The stream can't be iterated more than once, so Iterator is the correct representation.

Why you can't iterate stream multiple times?
 
It cannot implement Collection because the actual number of elements is not known up-front (Collection provides a size() method that could not be implemented). Clients and servers just stream messages until they are done without having to report the number at the start of the operation.

In this case Collection.size() would be blocking - wait until get everything. Hibernate does something similar when you're doing size() on lazy collection.
 
BTW, I don't see anything wrong in your code snippet. In fact, the Iterator sample is more concise and just as readable.
Both code snippests works 100% fine. just in my opinion for each looks better, using bare iterator is not frequent.

Eric Anderson

unread,
May 12, 2015, 12:40:50 PM5/12/15
to Martin Grześlowski, grpc-io
On Tue, May 12, 2015 at 7:19 AM, Martin Grześlowski <martin.gr...@gmail.com> wrote:
Only con against Iterable could be that you can invoke iterator() many times.

I think this is in fact the entire reason that it returns Iterator instead of Iterable. The stream can't be iterated more than once, so Iterator is the correct representation.

Why you can't iterate stream multiple times?

Because that would require one of two options:
  1. Storing all responses from server
  2. Storing request and then "replaying" the RPC to get another stream. Note that this doesn't actually solve the problem because the second iteration could return different results.
Both options are dangerous, as you almost certainly don't want them to happen without your knowledge.

It cannot implement Collection because the actual number of elements is not known up-front (Collection provides a size() method that could not be implemented). Clients and servers just stream messages until they are done without having to report the number at the start of the operation.

In this case Collection.size() would be blocking - wait until get everything. Hibernate does something similar when you're doing size() on lazy collection.

No, that would be an anti-pattern. Streaming should be streaming, not fully-buffering.

Note that some streams never naturally complete, such as a stream returning notifications.
 
BTW, I don't see anything wrong in your code snippet. In fact, the Iterator sample is more concise and just as readable.
Both code snippests works 100% fine. just in my opinion for each looks better, using bare iterator is not frequent.

Iterable would be nice, but using Iterator isn't that bad.

One possibility we considered is having an Iterable that would only allow you to call iterator() once; a second call to iterator() would throw an exception. That was the least-bad alternative, but it seemed abusing Iterator would just add to confusion for little gain.
Reply all
Reply to author
Forward
0 new messages