I\'ve created a linked list in java using generics, and now I want to be able to iterate over all the elements in the list. In C# I would use yield return
insid
Just to help readers understand the small details.
If you create a new list containing all the resulting elements and return the list, then this is a good implementation, simple enough to code. You can have as interesting data structure as you need, and when scanning it for the right entries, just return a list of all the matches, and your client will iterate on the list.
If you want to save a state, it may be more complicated. You'll need to get to where you've been every time your function is called. Not to mention re-entrant issues, etc.
The solution with threads does not create a new list. And it is as simple as the first solution. The only issue is that you involve a thread synchronization which is a bit more hard to code, and has its performance penalties.
So, yes, yield return is great and is missing from Java. Yet there are workarounds.
a yield return operation can be regarded as
therefore I implement it as a state machine alike class, coroutine. within this mechanism, each instruction has its instruction pointer, index, and instruction may has a label along with it, so we can use jmp(label) to jump to the label.
for example:
public class FibbonaciCoroutine implements Iterator<BigInteger> {
BigInteger[] bucket = { new BigInteger("1"), new BigInteger("1"), new BigInteger("0") };
int idx = 2;
Coroutine coroutine = new Coroutine((pthis) -> {
pthis.addInstruction("_label1", (me) -> {
int p1 = idx - 2;
int p2 = idx - 1;
if (p1 < 0)
p1 += 3;
if (p2 < 0)
p2 += 3;
bucket[idx] = bucket[p1].add(bucket[p2]);
idx = (idx + 1) % bucket.length;
me.yield(bucket[idx]);
});
// goto
pthis.addInstruction((me) -> {
me.jmp("_label1");
});
pthis.start();
});
@Override
public boolean hasNext() {
return !coroutine.isStopped();
}
@Override
public BigInteger next() {
while (coroutine.exec())
;
return coroutine.getYieldValue();
}
public static void main(String[] argv) {
FibbonaciCoroutine cor = new FibbonaciCoroutine();
for (int i = 0; i < 100 && cor.hasNext(); ++i) {
System.out.printf("%d ", cor.next());
}
}
}
see FibonacciCoroutine.java
"yield return" is a very sophisticated compiler trick. It basically lets you declaratively implement IEnumerable without any of the annoying details of "figuring out" how to build your iterator. The unfortunate thing is that it does not translate into other languages well because very few compilers have such a capability. In some ways "yield return" is as damning as revolutionary.
Basically in C#, the compiler will generate two implementations of IEnumerable and IEnumerator (of T). It does this by basically realizing your "method"'s local variables as instance fields in generated implementation classes as well as examining the frames containing a "yield return" artifact. Once you know this, it should be possible for a well rounded developer to accomplish the same thing explicitly... although not as concisely. To demonstrate, I will CONCAT!
public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y)
{
for(T e: x)
{
yield return e;
}
for(T e: y)
{
yield return e;
}
}
// becomes ....
public static <E> Iterator<E> concat_(Iterable<E> x, Iterator<E> y)
{
T e1, e2;
Iterator<E> i1, i2;
Iterator<E> s;
Iterator<E> s4 = new Iterator<E>()
{
public bool hasNext()
{
return false;
}
public E next()
{
throw ... ;
}
public void remove()
{
throw ... ;
}
}
Iterator<E> s3 = new Iterator<E>()
{
Iterator<E> act()
{
if(i2.hasNext())
{
return i2;
}
i2 = y.iterator();
return (s = s4);
}
public bool hasNext()
{
return act().hasNext();
}
public E next()
{
return act().next();
}
public void remove()
{
return i2.remove();
}
}
Iterator<E> s2 = new Iterator<E>()
{
Iterator<E> act()
{
if(i1.hasNext())
{
return i1;
}
i2 = y.iterator();
return (s = s3);
}
public bool hasNext()
{
return act().hasNext();
}
public E next()
{
return act().next();
}
public void remove()
{
return i1.remove();
}
};
Iterator<E> s1 = new Iterator<E>()
{
Iterator<E> act()
{
i1 = x.iterator();
return s = s2;
}
public bool hasNext()
{
return act().hasNext();
}
public E next()
{
return act().next();
}
public void remove()
{
return act().remove();
}
};
s = s1;
return new Iterator<T>()
{
public bool hasNext()
{
return s.hasNext();
}
public E next()
{
return s.next();
}
public void remove()
{
return s.remove();
}
};
}
public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y)
{
return new Iterable<T>()
{
public Iterator<T> iterator()
{
return concat_(x, y)
}
};
}
// tada!
If you all will pardon my 3AM pseudo java...
You can return an anonymous implementation of Iterable. The effects are pretty pretty similar, just that this is a lot more verbose.
public Iterable<String> getStuff() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
@Override
public boolean hasNext() {
// TODO code to check next
}
@Override
public String next() {
// TODO code to go to next
}
@Override
public void remove() {
// TODO code to remove item or throw exception
}
};
}
};
}