Programming Languages – Is Using ‘yield’ for Generators a Good Idea?

language-agnosticlanguage-designlanguage-featuresprogramming-languages

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.

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.

Poppycock. Do you really expect Random.Next or Console.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.

How does a function like this fit into the language paradigm? Does it actually break any conventions?

Yes, yield plays really badly with try/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).

Is it a good idea to have and use this feature?

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).

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?

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 any yields, 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.

Related Topic