Problem
I wrote an algorithm that returns all k-sized subgraphs of another given graph. Because I don’t want to make the runtime of the next() call of the iterator depended on k, I don’t want to return a new object every time. Instead I have one fixed instance-variable subG in the iterator that is changed between the calls und always represents the current subgraph that was calculated. It acts as a view that can be copied if needed if you want to use it further.
This method works fine and this is not my problem.
If I want to use hasNext(), I’d need to calculate the next subgraph, which would change the view subG as a side-effect. This is not wanted. Currently I’m using my own interface for this iterator:
/**
* Interface for all iterators that always return the same object, but change it in order to return the next value.
* Therefore, the object should not be changed unintentionally, because that would result in unwanted side-effects.
* This prevents the use of "hasNext()" as this would have to calculate the next value for the object, but this method
* is not expected to have side-effects. The only method that changes the object is generateNext(), which also is
* its only purpose.
*
* The standard pattern for using this interface would be:
* while (iter.hasCurrent()) {
* doSomethingWith(iter.getCurrent());
* iter.generateNext();
* }
*/
public interface BlindIterator<T> {
/**
* @return True iff the current element is a valid return.
*/
boolean hasCurrent();
/**
* @return Returns the current element, but does NOT generate the next element. This method can be called
* as often as wanted, without any side-effects.
*/
T getCurrent();
/**Generates the next element, which can then be retrieved with getCurrent(). This method thus only provides
* this side-effect. If it is called while the current element is invalid, it may produce and exception,
* depending on the implementation on the iterator.
*/
void generateNext();
}
I’ve never written something like this. Is there a better pattern for this, if any?
Solution
I think most people would be surprised and annoyed by an iterator that mutated previously yielded values every time you called next
. While it makes sense to take what you can from the concept of an iterator, the thing you’re trying to make isn’t an iterator. (Perhaps the idea of a “cursor” would be more applicable, IDK.)
Your proposed interface {hasCurrent, getCurrent, generateNext}
seems fine. I do have some questions/suggestions.
- If not
x.hasCurrent()
, doesx.getCurrent()
return null, or throw an exception, or what? - Depending on 1 (particularly if it doesn’t throw an exception),
.getCurrent()
sounds more like a read-only property, in which case just call it.current()
. (or maybe even just.value
) .generateNext()
specifically doesn’t make anything (because we’re supposing that would be expensive); it changes the thing in question. Therefore maybe call it.mutate()
or.becomeNext()
- A
void
return is usually a wasted opportunity, even if just for a little extra debugging context. Exactly what will be best to return here depends on exactly how this is going to be used. Returning boolean success might save you a call to.hasNext()
; returningT
might save you a call to.current()
. Probably boolean is better, but it’s hard to say.