Here's one way to think of it...
Let's say that I need to define a function which iterates over all of (say) the files in a directory structure; or over a list that's so big and hairy and enormous that I really don't want to have to
actually generate and store that list all at once so that I can then iterate over it.
So what I'm wanting to build is a function that, each time it is called, will return "the next" value to me .. the next filename in the directory, for example. Something like:
Code:
while (getNextFileName(&foo)) ...
(Note: I'm not trying to write in any
particular language here... merely to illustrate the essential concept.)
Now, this necessarily implies that the function that I wish to write (
getNextFileName()) must have, and must be able to preserve from call to call, some notion of
its internal state. It has to know which filename it returned to me "last time" so that it can correctly deliver the next one "next time."
Ordinarily, I would have to do this with some kind of cumbersome "internal-state record" that the caller must use one function to create, then must hand to me with each call, and then must dispose of:
Code:
stateRec = beginSearch();
while (getNextFileName(&foo, staterec)) ...
endSearch(stateRec);
It works. But it's clumsy. It obliges my caller to know something about how I work, and to obey the protocols correctly, or else I'll screw-up. This has also made
every piece of code that uses my function be semantically dependent upon me. If I wanted or needed to redefine that protocol, then every single bit of code that uses it must be found and, at the very very least, recompiled. Also, the code within my function is harder to write because it's sort of "inside-out." This is not
expressive of what I'd really like to be able to say here.
I'd really like to have a way for
the language to implement this notion of "internal state" so that I can write my function something like this:
Code:
int getNextFileName(char *filename) {
<<start searching>>
while <<there's another filename>> {
<<assign the filename to the buffer provided>>
yield(True);
}
<<clean up the search>>
return(False);
}
Each time the function executes
yield, it "returns to its caller" but
doesn't discard its internal state. When the next call occurs, the function won't start over at the beginning: it will
resume execution at the yield-point. This goes on, as many times as necessary, until the function finally executes
return.
And the caller does not (have to) know nor care just how I'm doing what I'm doing.) That can be a "big win."
This concept can be very useful if you want to, say, give the
effect of "iterating through some huge and hairy list" but you don't actually want to
store the list. You create a "stateful function" that
algorithmically produces each value when it's needed.
This concept also restores the notion that "an object, or a unit of code, ought to be self-contained
and subject to change without notice."
HTH...