Is "yield keyword" useful outside of an iterator block? [closed]
Asked Answered
P

3

9

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.

Popeyed answered 25/11, 2011 at 20:19 Comment(8)
Whoever came up with the line "return yield;" is an evil genius of epic proportions.Porringer
We have some very nice code base man! I asked this question cuz I was arguing against this kind of coding... I wanted to hear what the community thinks about itPopeyed
There's nothing inherently wrong with it - except maybe you could argue that the fact that it made you ask this question means it had potential to be confusing. The word quotient or ratio would have saved a lot of head-scratching :pPorringer
@GETah: there is no yield keyword in your example. In your example, "yield" is an identifier.Margaretmargareta
Well, may be this code was written before the yield keyword was introduced :-) or the author didn't know it was a keywordHaviland
I don't see why this should be closed. It wasn't a keyword, but then that's the real question.Hulking
I don't have a compiler in front of me but am surprised it doesn't have to be declared int @yield. I guess because it's not a contextual keyword unto itself.Gilmagilman
@JohnK it's precisely because it is a contextual keyword that you don't need to type @yield. Contextual keywords only function as keywords in a certain context. Non-contextual keywords like class are always keywords in every context, and therefore need to have an @ sign prepended if you want to use them as identifiers.Margaretmargareta
C
22

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?

Corpuscle answered 25/11, 2011 at 20:22 Comment(7)
Yes, this is exactly my pointPopeyed
@GETah: Well it's not really a keyword in the context you've given...Corpuscle
Jon, just testing my understanding here... Is the yield as used in the method such as my GetNotVeryRandomNumbers in my answer not in an iterator block? (i thought yield creates one, but doesn't have to exist within one). This seems to contradict your last statement.Rael
Re-reading, i think you mean it's yield break that has to be in an iterator block. I took you to mean both had to be in an iterator block.Rael
@GeorgeDuckett: Either of them turns a method into an iterator block. Have edited for clarity.Corpuscle
Ahh ok, so the method its self becomes an iterator block, thanks for teaching. :)Rael
+1 to the "return yield" could have existed prior to the introduction to the yield contextual keyword.Pagination
R
9

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

Rael answered 25/11, 2011 at 20:21 Comment(5)
I might be wrong, but I think this misses the point of the question. The question isn't "are iterator blocks useful?" - but rather: when used outside of an iterator block, is "yield" useful?Porringer
In the GetNotVeryRandomNumbers method it isn't in an iterator block (it creates one), or am i misunderstanding iterator blocks?Rael
With the edit, it's clear i definitely did miss the point of the question! (oops)Rael
@GeorgeDuckett I believe it is more accurate to say that the compiler treats the method as an iterator block than that the calling code does so. To the calling code, the method is just a method that returns an IEnumerable or and IEnumerator, or their generic counterparts. The calling code is unaware of the implementation detail (whether the method is coded as an iterator block or simply as returning an object implementing one of those interfaces). In other words, the compiler compiles the iterator block into a method returning an object implementing the appropriate interface.Margaretmargareta
@GeorgeDuckett now if only I could edit that comment to fix the monstrosity that is the last sentence.Margaretmargareta
M
5

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.

Miyamoto answered 25/11, 2011 at 20:21 Comment(1)
+1 for the link to your earlier interesting questionMargaretmargareta

© 2022 - 2024 — McMap. All rights reserved.