What is the difference between "yield return 0" and "yield return null" in Coroutine?
Asked Answered
C

2

15

I'm new and a bit confused about "yield". But finally I understand how it worked using WaitForSeconds

but I can't see the difference between of "yield return 0" and "yield return null".

are both them waiting for the next frame to execute?

sorry for my bad English. Thank you very much.

Cretinism answered 1/9, 2016 at 10:12 Comment(0)
C
29

Both yield return 0 and yield return null yields for a single frame. The biggest difference is that yield return 0 allocates memory because of boxing and unboxing of the 0 that happens under the hood, but yield return null does not allocate memory. Because of this, it is highly recommended to use yield return null if you care about performance.

Cluny answered 1/9, 2016 at 10:24 Comment(28)
Which boxing and unboxing are you talking about?Finale
@YuvalItzchakov The boxing of the 0.Efflorescence
@Efflorescence Where exactly that does boxing occur?Finale
@YuvalItzchakov When it is yielded.Efflorescence
@Efflorescence Why would it need to box?Finale
@YuvalItzchakov Because coroutines are of type IEnumerable, not IEnumerable<int>. When you store an integer in a variable of type object it needs to be boxed.Efflorescence
@Efflorescence coroutines implement IEnumerable<T> as well as IEnumerable. When iterating the iterator, it calls Current on IEnumerator<Int>, not IEnumerator<object>.Finale
@YuvalItzchakov Iterator blocks can be used to create methods that return IEnumerable<T>, but unity coroutines are going to be of type IEnumerable, not IEnumerable<int>.Efflorescence
@Efflorescence Ah, this is unity specific. Never the less, the creation of the state machine will incur an allocation anyway. Saying "always yield return null" seems to be a bad pattern to me.Finale
@YuvalItzchakov The fact that the state machine is going to allocate a new object for good reason doesn't mean you should be allocating new objects that accomplish nothing.Efflorescence
@Efflorescence Then use a const and return it each time. Don't micro-optimizing for no reason.Finale
@YuvalItzchakov Why would you need a const to hold null? There already is a constant for null. it's null. Why unnecessary allocate a new object for no reason? I would agree that it's not exactly the end of the world to have a boxed value, but there's nothing accomplished by using a value that is being boxed either. It costs you nothing to get the better performance.Efflorescence
@Efflorescence I didn't mean to hold a const with null. Hold a const that has a meaning, or use yield break. It costs you nothing to get the better performance, this has a hidden assumption that this is actually on some hotpath where the OP would actually gain anything from this micro optimization.Finale
@YuvalItzchakov What meaning do you intend to convey with that constant? The point of the value here is that it's not a value, which is exactly the semantics of null. What other semantics are you attempting to convey? yield break is just flat wrong. It wouldn't function properly. He needs to pause to the next frame, not end the coroutine.Efflorescence
As to performance, you're arguing for pointlessly performing an action that adds zero value at a (granted, fairly small) cost, for no reason. Do you just randomly go around your code inserting Thread.SpinWait for no reason into your code periodically "because it's not a hotpath, so it doesn't matter"? Additionally, this yielding is something that is going to be done throughout the app, so it will almost certainly actually be in many hot paths.Efflorescence
@Efflorescence LOL, you're making so many hidden assumptions while knowing nearly nothing about why the OP actually asked this question. I'm generally in favor of doing things the right way, before thinking "OMG is this going to add those extra 4 bytes to my GC pressure". Returning null can go wrong in so many ways, much more than adding this performance hit. I did not mean "return this useless junk of a value just to get to the next frame", but the OP should think semantically how he can return something with a meaning, instead of scattering null.Finale
@YuvalItzchakov I'm not making assumptions, I'm just leveraging some basic knowledge of Unity coroutines. The idiomatic behavior here is to yield null. This isn't going to go wrong in any ways. You're assuming that this is to be treated as a sequence of values, and it's simply not. That's not how unity uses its iterators. null is the most meaningful value to return because the point is that "no meaningful value" is what is being yielded, and null actually represents those semantics best. Certainly better than a number that means nothing.Efflorescence
@Efflorescence I'm not going to argue over that. If you really think that null is a good choice here, you probably know what you're talking about, I haven't done any Unity work. But to whomever reads this and make take this as a general C# advise, he's going to have a bad time, I would definitely not recommend returning null to represent an empty iteration semantics.Finale
@YuvalItzchakov This question is for Unity. It has Unity tagged on it not WPF or WinForm. Unity is a game engine. You can't do programming and not care about memory allocation like you can in a normal C# application. For example, if you do animation with yield return 0 in a while loop, then attach the script to 50+ gameobjects, that will cause garbage collector to be happening more often leading to game freezing and unfreezing at some certain point. This is not good on iOS or Android. You may call it micro-optimization or unnecessary but It is not.Cluny
@Efflorescence Thanks for answering those questions. Yuval thinks that because only 4 bytes is allocated, it is fine to use yield return 0. This is false in Unity. For example, the code while(moveObject){transform.position = ....; yield return 0;} will move the gameobject over time. This will run 60 times per-second and that is 240 bytes allocated per-second. Now, let's attach the script to other 50+ GameObjects that needs to move too. Now, we have a really big problems on mobile devices. I think you understand that. Hopefully, Yuval will. Happy coding!Cluny
@YuvalItzchakov I think you have no experience in gaming industry, especially with low-end mobile devices.. Most of the time, spending time on micro-optimization is bad, but I can't agree with you this time. Why bother choosing yield return 0, when you can just go with yield return null? Even Unity's official documents use yield return null. The reason why the OP asked this question was, there are also some example code with yield return 0 online. But most Unity programmers choose yield return null. And Servy's answer will add one more reason to that.Punishment
Also, focusing on micro-optimization is really bad, but if you can benefit a little more just by typing null instead of 0, why not choose the former? Gamers and mobile users really hate hiccups or lags. So you need to try hard to make your app run at 60+fps with a lot of GameObjects. Reducing unnecessary GC pause time is one of them.Punishment
@Punishment You're right, I have absolutely no experience in the gaming development. If you can decipline an entire team to always check enumerables for null, sure, go ahead and optimize. I'm just not sure how well that scales in a team.Finale
@YuvalItzchakov Well, more precisely, I had to say you have no experience with UNITY. You still don't understand what everyone's saying here at all.. yield return null or yield return 0 is just an idiom for WAIT TILL NEXT FRAME which is checked by Unity3d engine's special feature callled COROUTINE but not by OUR TEAM. 0 can be used just because it 's also interpreted as NULL under the hood. You can yield return many other Special Objects for Coroutine, but when you don't need any of them, then just null or 0. That's all. Why do you need any constant or meaningful specific number for this?Punishment
@Punishment No need to use caps :). If it's a special optimization for the engine, then great, again, something I didn't know.Finale
@YuvalItzchakov I didn't mean to be rude. I know you're an expert. I learned a lot from you on stackoverflow. But this time I couldn't understand why you kept fighting, and had to say it was different.. Unity3d is somewhat different. It uses very old Mono which is somewhere between .NET 2.0 and 3.5. It uses different GC system from today's Mono and .NET, it has old known bugs which .NET doesn't have.Punishment
@Punishment I'm no expert, just someone trying to help out. Sometimes, we have unnecessarily ego filled arguments, this is one of them and was a poor choice on my behalf, nothing more :)Finale
@Yuval Itzchakov Whatever you call yourself, you're helping many people :) In this special case, there was a misunderstanding, but it's also good I think. Still others can learn something from this.Punishment
R
-4

You could even just "yield return;" i think,the end result is the same, regarding the coroutine;

Yield return is like saying "Return control now to the caller, but when i am called again continue from my previous state"

Rummy answered 1/9, 2016 at 10:16 Comment(4)
Wouldn't that be yield break? As far as I am aware, yield return always needs an expression. And in that case, there won't be a continuation either since the enumerator has finished with yield break.Soinski
As Joey suggests, this wouldn't compile.Yerkovich
This is valid for UnityScript.Giralda
@Giralda C# was only tagged in this question + he did not mention that which would confuse so many people that will come across this answer.Cluny

© 2022 - 2024 — McMap. All rights reserved.