Search Unity

Dumb question: why not execute scripts in the order they appear on the inspector?

Discussion in 'General Discussion' started by Not_Sure, May 14, 2021.

Thread Status:
Not open for further replies.
  1. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    While we're at it I'll agree you're too narcissistic to consider anyone other than yourself to be correct. Either way it looks like a moderator had some fun in this thread so it looks like any disagreement we have will just turn into dust a day later.
     
  2. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Your projecting your own issues on me. Its you that are unable to see that other methods are better. I'm the first to admit when I am wrong. It does happen. Seldom
     
  3. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    Fixed that for you.
     
  4. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Code (CSharp):
    1. private IEnumerable<IMyComponent> _components;
    2.  
    3. private void Awake()
    4. {
    5.    _components = GetComponents<IMyComponent>();
    6. }
    Would then be

    Code (CSharp):
    1. private readonly IEnumerable<IMyComponent> _components;
    2.  
    3. public void MyClassConstructor(IEnumerable<IMyComponent> components)
    4. {
    5.    _components = components;
    6. }
     
  5. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    No, that's bad design lacking foresight.

    It works this way for a reason, and the reason is not rocket science. Because in game engines creation is not coincedent with initialization. It is more pronounced in C++ engines, where rather than using a constructor through "new" the object could've been created by a method mortals weren't meant to know, because this way reduces memory fragmentation.

    You're forgetting about important property of Awake:
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.Awake.html
    By the time the engine calls awake, entire scene graph has been constructed, all components are attached, all references are set. If Awake were a constructor, the scene at that moment would've been in an unknown and incomplete state. So any work referencing external objects would be delayed to a later point, and that later point would become Awake(). So even if the design was changed to what you propose, the method Awake() would emerge again as an entry point that is called when all scene has been built, and bulk of work would be done there, and not in constructor.

    Dealing with your proposition in situation when you have trees of objects with children and components will be a royal pain in the arse, because you'll have to account for things not being completely initialized upon being called, meaning you'll be unable to access external refs, and will have to account for object initialization order. That will inevitably give birth to the Awake we have now, where this problem is eleminated entirely, and when it is called, all objects are already valid.
     
  6. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    With proper constructor DI you wouldn't need hacks like FindByTag. Using find by tag is a sure way of creating a unmaintainable mess. In fact we don't have a single tag in our game.

    With constructor injection the entire prefab and its child components would be neatly packed in memory not the other way around.
     
  7. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    We don't need it even without DI except perhaps with MainCamera which is forced on us by Unity.
     
  8. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Yeah so his argument is even more void

    Edit: MainCamera isn't a requirement btw. Atleast not in VR that we are doing
     
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    You are missing the obvious.

    It is not about "FindByTag", it is about scnenegrpah being fully constructed when Awake() is called.

    In situation when there's only constructor, the constructor will be called when the rest of the scene isn't ready. For example, if you have a gameobjct hierarchy for the soldier in a scene, then you won't be able to reference a toe from a thumb and vice versa and have both references be valid within constructor. One of them will be constructed first while the other is still missing.

    Bypassing this problem would require jumping through the hoops. However, the problem can be completely destroyed by simply moving initialization into Awake().
     
  10. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    The argument isn't void, you simply don't get it.

    I would advise to learn C++ and spend a few years trying to write your own engine from scratch. Then you'll personally step on every landmine of the design you've proposed.

    Your proposition requires more code, has shortcomings, and Awake() is easier to work with. Hence your proposition is inferior.
     
    angrypenguin likes this.
  11. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    On the contrary constructor DI helps the developer not construct invalid and strange dependency trees. In my day job when someone have worked around constructor DI with property injection it can be refactored into more clean code with proper construxtor DI.

    I'm not saying we should shoehorn in constructor DI into unity at this point, but it would have been nice if it was deisgned with it from the start.

    Edit: also it's main usage wouldn't be injecting components in hierarchy but rather services.
     
    Last edited: May 16, 2021
  12. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    No.

    A developer using Awake() does not need any help in the first place. Awake() correctly works out of the box, handles all corner cases and is trivially easy to understand. Hence your proposal is pointless, as it does not solve any problem and you increase amount of code while achieving nothing.

    Here's a basic example.
    Code (csharp):
    1.  
    2. public class Blah: Monobehavior{
    3.     [SerializeField] OtherObj otherObj;
    4.     void Awake(){
    5.          if (otherObj)
    6.               otherObj.Stuff()
    7.     }
    8. }
    9.  
    In this scenario otherObj can refer back to Blah and it will still work as is. Everything is valid, no need for dependency injection.
     
  13. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    It wouldn't be a replacement for inspector set members. It would be a complement. Plus it would mainly be used for injecting services not hierarchy components.

    Edit: though I really hate how we are forced to mutable members without readonly keyword
     
  14. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Think a bit longer about it.
    Code (csharp):
    1.  
    2. public class Child: MonoBehaviour{
    3.      Parent parentObj;
    4.      void Awake(){
    5.           parentObj = GetComponentInParent<Parent>();
    6.      }
    7. }
    8. public class Parent: MonoBehaviour{
    9.      Child childObj;
    10.      void Awake(){
    11.           childObj = GetComponentInChildren<Child>();
    12.      }
    13. }
    14.  
    You can try reducing number of lines here.

    It solves nothing. And it is inferior to current approach. Hence it is pointless. And even as complement it is inferior to current approach. I already explained to you why.
     
  15. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Its not about number of lines. Its about immutability. And testability.
     
  16. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571

    I believe you need to rethink your life choices.

    You don't need any of that to make a game, and if you ditch "testability" and "immutability", and simply focus on writing SIMPLE and READABLE code, you'll increase your development speed by factor of ten or more, while creating a codebase that will be easier to maintain than what you have now.
     
    JoNax97, NotaNaN and Ryiah like this.
  17. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    That view on QA is why we have games like Cyberpunk :p

    edit: we have a custom lightweight DI with property injection so we have solved it anyway. But mutable.
     
  18. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Most likely, it is other way around.

    When somebody is insane enough to waste time writing hundreds or thousands of lines of code just to adhere to some sort of cargocult and the same task can be done in 5 lines of code, they'll miss the deadline and the result will be another cyberpunk.

    If you want to make a point, take my code example with Parent/Child, and make it shorter and easier to read using your principles. If you can't, then perhaps it is the time for you to rethink the principles you worship.

    You haven't solved it, you got distracted, and wasted time fighting a non-existing problem that didn't even need fixing. Good job. You could've spent this time implementing vehicles or dogs in your game.

    And that's how we get situations like Cyberpunk. At least one of the many ways.
     
    NotaNaN and Ryiah like this.
  19. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    I did say its mainly used for services. How many unit tests you have in your project? How much code do you need to write to replace services in that test to mocked versions of said services?

    Also alot of bugs steam from mutable members. Why you think Microsoft included the keyword otherwise

    edit: with a proper DI framework you can also have scopes. For example then you can have a event bus that only fires event within a certain scope. We use this all the time in our game. For example to propagate events inside a firearm.
     
    Last edited: May 16, 2021
  20. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Your entire approach is fundamentally wrong. You are also not microsoft and are not making a service but a game. What's more you're note programming it from scratch, and instead use C# as a scripting language.

    The point is to ditch every single thing you listed, make the codebase compact and small, and produce the result using a tiny number of classes with short methods. A game like a first person shooter does not need a lot of classes in the first place and does not have a lot of complexity.

    What you're currently doing is writing bloat that has no effect on gameplay and does nothing other than wasting development time and money. That is a breach of KISS/YAGNI, and that's the wrong way to approach the problem.

    Like people said, that's not an enterprise application.
     
    NotaNaN, Ryiah and Lurking-Ninja like this.
  21. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    A game have plenty of services, sub systems, etc call it what you want. In a proper unit test you want to remove as much of these as possible and only test one component at the time, mock the rest. Some services might not be able to unit test at all easy. For example your network layer. You mock these.
     
  22. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Kill your DI framework, kill your event bus, kill your services, all unit tests, scrap your entire codebase, and start over from scratch while adhering to KISS/YAGNI and component-based approach. Do not implement a single thing unless it has direct impact on gameplay. Treat each object as a completely independent drone in a physics sandbox.

    If you manage to "get it", you'll redo every single thing you have right now in 3 to 6 months and the result will be a superior product.

    Currently you fell into programmer's trap and are victim of what I call "Amazingly interesting problem". Which is a situation when you try to solve some "issue" that has zero impact on functionality of the product and spend inordinate amount of time "fixing" it, except that once you've solved it, the solution will have no impact on functionality.

    I've learned to avoid this crap several years ago, and I advise for you to do the same. For you it hasn't clicked yet.
     
  23. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    No, that's nonsense.

    You aren't writing a game engine, you're writing a game in unity.

    The subsystems and services has been already provided to you, so you're only writing glue code, building on TOP of them, and you write it in a way that does not require testing. And even in case of Networking there are libraries that has been used successfully, like Mirror.

    Here's an example of a successful game made with Mirror.
    VR title with guns, building and ability to fly. Highly popular.
    ---------

    Anyway, I'm done discussing. Hopefully one day you'll snap out of your current practices, because once the approach I described "clicks", it is one of the amazing feelings you can experience while programming.
     
    NotaNaN and Ryiah like this.
Thread Status:
Not open for further replies.