PDA

View Full Version : C++ and C#



mickey
30th November 2007, 23:35
Hello,
Do anyone know if how to implement something like istruction C# "yield" ??? (it permit to return a value (eg during a loop for) to another function and keep alive the environment).

wysota
1st December 2007, 00:25
Actually this instruction is not C# originated. I know it was present in at least Python before that. The easiest way is to use a static local variable holding the last returned result and continue from there during the next call.


int getNextNatural(bool restart=false){
static int last = -1;
if(restart)
last = -1;
return ++last;
}

mickey
1st December 2007, 11:01
But I meant a bit more...


vector<Element> Elements // 20 elements suppose

foo1() {
foreach (Element e in checkForSomething(e)) {
print (e.name);
}

IEnumerable<Elemement> checkForSomething(e) {
//iterator on Elements = eIt
int a = 10; //it'll keep alive
for(; eIt.MoveNext() ) { //movNext go on.....
if (e.value ==2)
yield return e;
}
}
//main
foo1();

when a Elements is ok, it's returned to foo1 and printed; after the control goes again inside checkForSOmething() (exactlly after the yield) and it restart from inside for at point it left......

wysota
1st December 2007, 12:15
Exactly what my code does... Make the iterator static and voila...


... {
static XXX::const_iterator iter = e.begin();
while(iter!=e.end()){
//...
return sth; // yields the iteration
}
}

Next time you call the method, it will skip the initialization of the iterator and continue from where it left.

mickey
1st December 2007, 16:29
yes, I could declare as static 'a' too....but when are these 'static' variabile deallocated? When program end, I guess...

wysota
1st December 2007, 16:43
I don't know what "a" does in your case because you don't use it anywhere, but yes, you may declare it static as well :) Static variables are never deallocated. They are destroyed together with global variables.

mickey
2nd December 2007, 00:47
Hello,
'a' does nothing in my case. I'm looking for C# vs C++; with your code it's possibile to have something similar to yield; BUT: in my example what happen inside "for (moveNext)" is very simple; if I had many variabile, eg. "int a,b,c,d" or some large objects, I guess I have to declare they as statics -> they'll be keep alive until the application end! It seems a very waste of memory. Are we sure what is behind yield istruction does the same thing?? (ie work as "static" c++).

Thank in advance.

wysota
2nd December 2007, 10:19
Look - you are trying to emulate a construction of another language that doesn't exist in C++, so you have to accept some drawbacks of such solutions. I'm sure you can try to emulate yield using some mapping between objects and their current states to avoid static variables, but it's a bit more work. C# also has to keep those objects in memory because you might always want to call the function again and the state of the run has to be kept somewhere.

But this is all unimportant - what is important is that C++ doesn't use a construction such as yield. In C++ you'd simply use an iterator passing it as an argument to the method (maybe even as a reference), like so:

int func(std::vector<int>::const_iterator &iter){
int val = *iter;
++iter;
return val*2;
}

In this function iter gets updated to point to the next entry, so next time you call the function, it will operate on the next index (provided that the iterator remains valid and unchanged).

Methedrine
2nd December 2007, 13:00
Actually it should be possible to emulate the whole IEnumerable interface with a class wrapping around a simple list structure.

wysota
2nd December 2007, 13:03
Isn't it what iterators do?

Methedrine
2nd December 2007, 13:09
Isn't it what iterators do?

Yes, it is almost exactly the same. The difference simply is that the yield keyword and the IEnumarable interface hide the whole iterator concept, and as such adds nothing but some syntactic sugar (to some, at least).

wysota
2nd December 2007, 13:26
Consider the following example:

SomeContainerObject Elements;
MyIterator iter(Elements);
while(iter.hasNext()){
Element e = iter.next();
doSomething(e);
}
Isn't this exactly what is searched for? And this is exactly a typical iterator. Of course hasNext() and next() have to be implemented in such a way that they perform the same function what the yieldable function does.

What is vital is that the iterator keeps an internal state of "index" in the iterated object. Then it's just a matter of generating elements. Of course the object doesn't even have to be a container - in that case the iterator becomes a simple generator function, like this:

class Generator {
public:
Generator(int start){
m_curr = start;
}
bool hasNext(){ return true; /* neverending story */ }
int next(){ return -(m_curr++); }
private:
int m_curr;
}
The above object keeps returning negations of increasing numbers starting from the number passed as the argument for the generator. It's similar to:

int fun(int s){
int x = s;
while(1){
int r = -x;
x = x+1;
yield r;
}
}