Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Be careful about run order of Awake functions

Discussion in 'Scripting' started by mahdiii, Jan 23, 2018.

  1. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793
    Hi
    I intend to explain why run order of Awake functions is vital because it can cause weird behaviours.
    I don't know the reason why unity executes Awake functions without any order.So if awake functions depend on together, in every execution you may see different behaviours
     
  2. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    6,422
    Joe-Censored, lordofduct and mahdiii like this.
  3. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    760
    You could use events to daisy-chain the initialization in the order you want I suppose, but it's far easier to just divide the job between Awake and Start as @LaneFox said.
     
    mahdiii likes this.
  4. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793
    yes but in singleton design pattern you initialize them in Awake. They can depend on together
    I know we can use the following ways:
    1- lazy initialization
    2- give orders with Edit->Script Execution order
    3- initialize them in one main entry point
    4- use service locator
     
  5. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793
    and why does unity implement them like this,random orders!
     
  6. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    6,422
    It is not random, as already stated. Study the links if it's not clear to you.
     
    lordofduct likes this.
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,358
    It's not a random order.

    It's an undefined order.

    From my practice, the order appears to be the order of the GameObject's the components are attached to in the hierarchy, from top to bottom. Child GameObjects are called starting deep and backing out. (Execution Order taking precedence over this of course)

    But Unity has this order undefined, because they don't want you relying on any defined order. If they did define it, then they could never change it. If down the line they wrote a faster/efficient initialization algorithm, but required changing the order, by defining it they wouldn't be able to change.

    So instead they tell us users to not expect it to be in any particular order. And to use Awake/Start to do any ordering.

    In the case of Singletons... as you your self brought up, you have 4 alternative ways to deal with the ordering issues.

    Personally I have foregone singletons for the most part. In my latest version of spacepuppy I have only 1 true singleton left. And I have migrated everything else to a service locator system.
     
    Suddoha and mahdiii like this.
  8. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793
    So you say it is not random and in a build version or editor they are called the same?
    Because I see myself that my game was executed differently in build and editor
    In editor it was completely true and expected
    When I added the singleton in the execution order correctly, it was run appropriately in build as well!
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,358
    Different builds may have different orders.

    My point is that it's not random.

    It's undefined.

    Unity doesn't just randomly select objects to initialize. There's a method to the madness behind the scenes. We just don't know WHAT that method is. And that method may vary from target platform to target platform. I can see different algorithms being used because different ones may be better optimized for specific platforms.
     
    RecursiveFrog likes this.
  10. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793
    I didn't change the platform (Always android). Thank you
     
  11. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,358
    Android is a different platform than the editor running on Windows/Mac/Linux.

    I'm also not saying that it *does* do this, I'm saying that I can understand *why it could* do this.

    In the end... it's undefined, so all of our guesses are the best we can say.
     
  12. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    6,422
    The solution is to design scripts that work and support each other in the given circumstances. The documentation explains that you are guaranteed to get every Awake() call before Start(), and you are guaranteed to get all Start() calls before any Update() call. You also have the option of forcing a sequence of scripts to get their calls via the Execution Order panel.

    That is enough structure to guarantee safe initialization and communication of scripts, you just have to design within those features.
     
    Suddoha, lordofduct and Lysander like this.
  13. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,336
    This. You can't say that often enough. :D

    @mahdiii
    Even when Singletons are used, you can still resolve most of the dependencies if you use Awake and Start correctly.

    Anyway, similarly to @lordofduct, I also decided to design my modules and systems without singletons. There's at most just one singleton in my current framework and that's just for the common quick start (it's basically the application's root "container" or context that provides access to all modules / systems - either instantly or lazily, i.e. on demand). It doesn't even need to be a singleton.

    Early in the days I was kind of in love with singletons. It was my very first widely-used design pattern. It was easy to access the instance from literally everywhere (which is actually a problem), easy to code (there are some common pitfall in Unity but it's not difficult either) and people who read the code immediately understand what's being accessed there and can adapt that.

    But after
    1) further extensive research about the pattern and also relevant topics (such as an overuse / misuse of statics)
    2) various approaches to code singletons in a more flexible way
    3) much unit testing

    they always revealed the ugliness and pain that comes with singletons in big projects once they're introduced on higher layers. There are still ways to work around some of the major problems, but I personally wouldn't use these anymore.

    This also changed my mind about DI and IOC in general, as I first thought it was just one of these hypes and put it aside evily smiling at it. I still don't use DI frameworks (rather my own system which adapts a few ideas), but it's a powerful approach to eliminate some major design flaws when it comes to resolving dependencies.
     
    Last edited: Jan 23, 2018
    mahdiii likes this.
  14. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,470
    whats so hard about this, setup the internal state of your object in Awake, then if you need to talk to other objects do it in Start
     
  15. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    793

    My problem was not about Awake Start, it was about OnEnable and Awake.
    See like below:
    Code (CSharp):
    1. public void OnEnable(){
    2.    CEventManager.GetInstance().AddListener("EventName",OnEvent);
    3. }
    4. public void OnDisable(){
    5.       CEventManager.GetInstance().RemoveListener("EventName",OnEvent);
    6. }

    You know that OnEnable can be executed before some Awakes(other Awakes that don't belong to the gameobject)

    Maybe it was better to write:
    Code (CSharp):
    1. public void Start(){
    2.    CEventManager.GetInstance().AddListener("EventName",OnEvent);
    3. }
    4.  
     
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,358
    mahdiii and Suddoha like this.
  17. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    6,115
    This is the first time you've mentioned OnEnable in this thread. For future reference, perhaps you could describe the entire problem instead of expecting us to read your mind.

    It's true that A's OnEnable might be called before or after B's Awake if both are in the scene at the start of the scene. So if CEventManager's instance is null because its Awake hasn't been run yet, that OnEnable might break. As mentioned, you simply need to design within the system that exists.

    Perhaps something like this would work. This will add and remove the listener as designed in your first attempt, but will also work if this object runs OnEnable before CEventManager's Awake.
    Code (csharp):
    1.  bool listenerAdded = false;
    2. public void OnEnable(){
    3. if (CEventManager.GetInstance() != null) {
    4.    CEventManager.GetInstance().AddListener("EventName",OnEvent);
    5. listenerAdded = true;
    6. }
    7. }
    8. public void Start(){
    9. if (!listenerAdded) {
    10.    CEventManager.GetInstance().AddListener("EventName",OnEvent);
    11. listenerAdded = true;
    12. }
    13. }
    14. public void OnDisable(){
    15.       CEventManager.GetInstance().RemoveListener("EventName",OnEvent);
    16. listenerAdded = false;
    17. }
     
    KWaldt, mahdiii, LaneFox and 2 others like this.
  18. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,358
    I will point out... this is similar to a conversation we all had in another thread.

    Mahdii you have a knack for leaving out key information about the conversation (like the use of OnEnable, this is the first you mention it in this conversation). This confuses everyone as you talk about things in strange absolutes that don't apply to the context up to the point you mention new information.
     
    LaneFox and StarManta like this.
  19. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,336
    Oh, you did not say that explicitly in your first post. Now that's some information you should have added earlier.

    That's true, but a simple "yes, do it like that" is not always sufficient. You may still want to add/remove when enabling/disabling the component.
    There's a little more to that but it's not that tricky either, I've seen some solutions already on the forums.

    *EDIT
    Just saw @lordofduct has already linked his approach. You may wanna look at that.
     
    mahdiii likes this.
  20. Lumpazy

    Lumpazy

    Joined:
    Apr 24, 2018
    Posts:
    5
    How nice would it be if there was :
    Awake (unspecified order)
    Awoken (now all are awake and can talk)
    OnEnable (now i need to do something)
    Start ..
    Why specifically does Unity do OnEnable before Start ?
    Usually Onenable will be needed often. With values that may depend on other scripts having executed.
    So why iniztialize in start ???
    Or at least ... as above. Make a prewarmup = awoken...
     
  21. RecursiveFrog

    RecursiveFrog

    Joined:
    Mar 7, 2011
    Posts:
    126
    Because you can’t start something if it isn’t enabled. As far as Unity is concerned, anything that isn’t enabled can be treated as not participating in the engines lifecycle. If it’s not in the lifecycle it cannot Start.

    Likewise, disabling something doesn’t destroy it. It’s simply taken out of the lifecycle for a time. Re enabling won’t cause a reawaken or a restart.
     
  22. smallstep

    smallstep

    Joined:
    Jan 25, 2016
    Posts:
    28
    I'm in the same situation, with a (single) "AppServicesHolder" singleton of which the Awake runs *after* an MB's OnEnable that tries to use the singleton.Both are root GOs inside the "loading..." scene.

    What I did was to put the singleton prior to the "Default Time" in editor: scripts execution order. However I would love to give a better (yet simple and future-proof) solution to this issue. Any ideas?
     
  23. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    760
    Daisy chaining delegate events is probably the only way for something completely in C#. I'd say the Unity way is more convenient since there's lesser setup, whether its future proof or not, hard to say.
     
    smallstep likes this.