Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!agate!shelby!csli!poser From: poser@csli.Stanford.EDU (Bill Poser) Newsgroups: comp.lang.c Subject: Re: Coroutines in C Message-ID: <10109@csli.Stanford.EDU> Date: 16 Aug 89 21:43:05 GMT References: <5663@ficc.uu.net> <14281@haddock.ima.isc.com> <563@augean.OZ> <10097@csli.Stanford.EDU> <5710@ficc.uu.net> Sender: poser@csli.Stanford.EDU (Bill Poser) Reply-To: poser@csli.stanford.edu (Bill Poser) Organization: Center for the Study of Language and Information, Stanford U. Lines: 70 In article <5710@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: >Generators in 'C'... I guess you could use coroutines to implement >something like Icon generators, but Smalltalk generators might be >easier. There's more to Icon generators than the function itself... >how do you do !every write(factor(192))!? It seems to me that this question confuses implementation of generators, that is, having multiple calls to factor() return the several factors, and goal-oriented evaluation, where the "every" construct (as well as others, some implicit) causes write() to be called until it fails which in turn causes factor() to be called until it fails, which happens when it runs out of results to return. Goal-oriented evaluation a la Icon does indeed require more than saving stack frames, but implementing the generator itself doesn't. >Generators in Smalltalk are implemented differently than in Icon. >You set up methods for getting the first and next element of the >sequence, and use instance variables (if necessary) to maintain >state. This is more conventional, and wouldn't require coroutines. I'm not sure I understand how this solves the problem. Using instance variables is pretty much like using statics in C to store the state information, but the real problem is in implementing the method for getting the next element in the sequence. It is that method that is going to need the state information, and when the control structure gets even moderately complicated, saving the state information without saving the whole stack frame gets to be a pain. For example, here is a generator that returns pointers to strings matching a given regular expression. The array commands contains structures whose name member is a character pointer. comcnt is the number of array elements. char * AproposBuiltins(re) regexp *re; { static int i = 0; char *retval; while(i < comcnt){ if(regexec(re,retval = commands[i].name)){ ++i; return(retval); } else ++i; } /* If we get here there are no more matches */ i = 0; /* Reset for next search */ return((char *) 0); } We make the loop index static and we also have to complicate the control structure a bit over a simple loop traversal, but it isn't too bad. How about traversing a two dimensional array? We would not only have to make both array indices static, but we would have to keep track of whether it was time to increment the outer loop index or whether we should reenter the inner loop right away. But if we save the stack frame, including not only the auto variables but the program counter, we have all the information we need no matter how complex the control structure. What is similar to coroutine support is language support for the equivalent of the Icon "suspend" primitive, which returns a value but saves the stack frame. To my (limited) knowledge, Smalltalk does not provide support for this. Isn't the Smalltalk method of implementing generators just doing it by hand as in the above C example, with instance variables playing the role of statics?