Is "yield keyword" useful outside of an iterator block?

831 Views Asked by At

The yield keyword documentation says:

The yield keyword signals to the compiler that the method in which it appears is an iterator block.

I have encountered code using the yield keyword outside any iterator block. Should this be considered as a programing mistake or is it just fine?

EDIT Sorry forgot to post my code:

int yield = previousVal/actualVal;
return yield; // Should this be allowed!!!???

Thanks.

3

There are 3 best solutions below

7
On BEST ANSWER

It's okay to use yield outside an iterator block - it just means it isn't being used as a contextual keyword.

For example:

// No idea whether this is financially correct, but imagine it is :)
decimal yield = amountReturned / amountInvested;

At that point it's not a contextual keyword (it's never a "full" keyword), it's just an identifier. Unless it's clearly the best choice in terms of normal clarity, I'd try to avoid using it anyway, but sometimes it might be.

You can only use it as a contextual keyword for yield return and yield break, which are only ever valid in an iterator block. (They're what turn a method into an iterator.)

EDIT: To answer your "should this be allowed" question... yes, it should. Otherwise all the existing C# 1 code which used yield as an identifier would have become invalid when C# 2 was released. It should be used with care, and the C# team have made sure it's never actually ambiguous, but it makes sense for it to be valid.

The same goes for many other contextual keywords - "from", "select", "where" etc. Would you want to prevent those from ever being identifiers?

1
On

yield is a contextual keyword.
When used in yield return or yield break, it is a keyword and creates an iterator.
When used elsewhere, it's a normal identifier.

yield can be extremely useful for more than ordinary collections; it can also be used to implement primitive coroutines.

5
On

What that is saying is that if you use yield in a method the method becomes an iterator block.

Also, as yield is a contextual keyword it can freely be used elsewhere, where full keywords can't (e.g. variable names).

void AnotherMethod()
{
    foreach(var NotRandomNumber in GetNotVeryRandomNumbers())
    {
        Console.WriteLine("This is not random! {0}", NotRandomNumber);
    }
}

IEnumerable<int> GetNotVeryRandomNumbers()
{
    yield return 1;
    yield return 53;
    yield return 79;
    yield return 1;
    yield return 789;
}

// Perhaps more useful function below: (untested but you get the idea)
IEnumerable<Node> DepthFirstIteration(Node)
{
    foreach(var Child in Node.Children)
    {
        foreach(var FurtherChildren in DepthFirstIteration(Child))
        {
            yield return FurtherChildren;
        }
    }
    yield return Node;
}

See also: This answer, which shows using one yield after another. Clever Uses of Iterator Blocks