PHP, C#, Python and likely a few other languages have a yield
keyword that is used to create generator functions.
In PHP: http://php.net/manual/en/language.generators.syntax.php
In Python: https://www.pythoncentral.io/python-generators-and-yield-keyword/
In C#: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield
I am concerned that as a language feature/facility, yield
breaks some conventions. One of them is what I'd refer to is "certainty". It is a method that returns a different result every time you call it.
With a regular non-generator function you can call it and if it is given the same input, it will return the same output. With yield, it returns different output, based on its internal state. Thus if you randomly call the generating function, not knowing its previous state, you cannot expect it to return a certain result.
How does a function like this fit into the language paradigm? Does it actually break any conventions? Is it a good idea to have and use this feature? (to give an example of what's good and what's bad, goto
was once a feature of many languages and still is, but it is considered harmful and as such was eradicated from some languages, such as Java). Do programming language compilers/interpreters have to break out of any conventions to implement such a feature, for example, does a language have to implement multi-threading for this feature to work, or can it be done without threading technology?
Best Answer
Caveats first - C# is the language I know best, and while it has a
yield
that seems to be very similar to other languages'yield
, there may be subtle differences I am unaware of.Poppycock. Do you really expect
Random.Next
orConsole.ReadLine
to return the same result every time you call them? How about Rest calls? Authentication? Get Item off a collection? There are all sorts of (good, useful) functions that are impure.Yes,
yield
plays really badly withtry/catch/finally
, and is disallowed (https://blogs.msdn.microsoft.com/ericlippert/2009/07/16/iterator-blocks-part-three-why-no-yield-in-finally/ for more info).It's certainly a good idea to have this feature. Things like C#'s LINQ is really nice - lazily evaluating collections provides a big performance benefit, and
yield
allows that sort of thing to be done in a fraction of the code with a fraction of the bugs that a hand-rolled iterator would.That said, there's not a ton of uses for
yield
outside of LINQ style collection processing. I've used it for validation processing, schedule generation, randomization, and a few other things, but I expect that most developers have never used it (or misused it).Not exactly. The compiler generates a state machine iterator that keeps track of where it stopped so that it can start there again the next time it is called. The process for code generation does something akin to Continuation Passing Style, where the code after the
yield
is pulled into its own block (and if it has anyyield
s, another sub-block, and so on). That's a well known approach used more often off in Functional Programming and also shows up in C#'s async/await compilation.No threading is needed, but it does require a different approach to code generation in most compilers, and does have some conflict with other language features.
All in all though,
yield
is a relatively low impact feature that really helps with a specific subset of problems.