Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Public Component Vs Private GetComponent

Discussion in 'Scripting' started by ricardoCoelho, Apr 1, 2021.

  1. ricardoCoelho

    ricardoCoelho

    Joined:
    Jul 6, 2020
    Posts:
    18
    Hey guys, in alot of code examples I see the following

    Code (CSharp):
    1. private Transform _trf;
    2. void Start()
    3. {
    4.    _trf = GetComponent<Transform>();
    5. }
    instead of
    Code (CSharp):
    1. Public Transform Trf; //Set manually in the inspector.
    Is this because of teaching/simplifying purposes? Is it a standard in Unity development?
    Because the one that makes more sense to me is the second.
     
  2. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    It´s not needed to set it seperatly in the inspectory, because your component has it already (i think it comes from the MonoBehavior, but not sure), so it doesn´t make sense to set it by yourself.
     
  3. ricardoCoelho

    ricardoCoelho

    Joined:
    Jul 6, 2020
    Posts:
    18
    When you set it manually, the reference is already assigned at runtime. When you use the GetComponent, some processing power is required.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    It's the same, trust me. When you drag it in the inspector, Unity just does the GetComponent for you. And that will NEVER be a performance bottleneck.

    The biggest deal is the confusion that follows when you make something public so that you CAN drag it in with the inspector, and then still blindly wipe it out in Start() by using GetComponent().

    It should only be either one or the other, because there is ultimately only going to be ONE value in there. Don't muddy the intention.

    That said, another common mechanism is to make the field optional by allowing the user to drag something in, then in Start() doing a check, and if they did NOT drag it in, then use GetComponent(). This is reasonable, but if you're not thinking that might happen, it can be confusing.
     
  5. ricardoCoelho

    ricardoCoelho

    Joined:
    Jul 6, 2020
    Posts:
    18
    Sorry but I find it that hard to believe. I understand in terms of performance the difference may be minimal, but the same thing, I don't think so. Do you have any research to prove it?
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Belief is best-suited to religious institutions and perhaps horse betting.

    This is a software engineering effort: 1s and 0s are changed into other 1s and 0s. That's all.

    Help yourself. You can start with Window -> Analysis -> Profiler
     
    lordofduct and Lekret like this.
  7. stain2319

    stain2319

    Joined:
    Mar 2, 2020
    Posts:
    417
    As an amateur/hobbyist coder (who also works in tech) I think a lot of coding "standards" that you see are really intended for teams of people or for code that might need to be maintained by someone else later. If you have never seen code before but you need to modify it, it makes sense to follow certain protocols. Additionally, there might be situations where your code interacts with code someone else is writing and needs to follow certain standards for interfacing so that you don't step on each other's toes.

    I agree that performance differences would be negligible for the situation described.

    And if you're a solo coder working on your own project non-professionally you can do whatever is the most sensible to you and easiest for you to understand. One of the hardest things to learn as a new coder, I think, is that there aren't that many truly wrong answers as long as you're arriving at the end result you want.

    A programming language is a big box of legos. We might both want to build a lego house but neither one of our houses will look exactly the same and that's okay.
     
    Kurt-Dekker likes this.
  8. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I've seen performance improvements during prefab instantiation replacing a large number of GetComponent calls to scripts attached to the same prefab with inspector references. Stutter on instantiation disappeared. So I have a hard time believing Unity just runs GetComponent under the hood.

    But I did not investigate the issue very far or use the profiler on it. So can't say with any authority.
     
  9. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    My general rule is if I'm not going to change it, use GetComponent, because why drag it in? This also prevents it from going null if you click Reset on the script, which I do to sync any variables that have changed. Then you'd need to drag it in again.

    However, I had a project where I was getting a bunch of gameobjects (tiles) at Start() and storing them in an array. The order in which it got them was never the same twice, which caused issues. So I made the arrays public and dragged them in, voila, no more order issues.

    Also, in case anyone missed it...you can drag lists of objects into array slots in the Inspector and they will all populate at once, in their original order. Example: 10 sound effects you have in your Assets, highlight them all and drag to the array (the main name for the array, not any specific slot).Dragging objects from the Hierarchy does the same. Saves a ton of time.
     
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    It's true, Unity doesn't actually do GetComponent.

    When it's deserializing the related yaml/binary data for the scene there is a reference id that is used to find the related UnityEngine.Object within a lookup table. So the performance is different.

    But the performance is so fast for both GetComponent and this lookup table that you're likely not going to see it except in extreme situations. As to which is more performant... :shrug:...

    Now to the general thread/OP...

    My thing is that they're fundamentally different from a behaviour perspective.

    As Kurt-Dekker pointed out:
    Private with GetComponent implies that the component should only EVER come from the self. Often if you go this route you should pair it with the [RequireComponent(typeof(ThatComponentType))] attribute to avoid issues if you forgot to add the needed component since it may or may not be there.

    Public set through the inspector implies that this is configurable and that the component we reference could come from anywhere.

    Think like if you had a component that takes a Renderer, and it constantly manipulates the texture and sets it to that renderer's material.

    This script only really needs to care what Renderer it modifies, so it doesn't matter where it comes from. So having it public/serialized like that is nice. It means I can toss the component elsewhere (like on a child GameObject or something) and it'd still work.

    But say a 'follow script' with a Transform ref... well that NEEDS to be something other than itself. So it HAS to be public. Because if it got its own Transform well... it's now following itself (doesn't move?).

    But alternatively say you had script that expected everything to be local to itself. Like a player manager script that wants to access the transform, health, etc of that specific GameObject its attached to. Referencing any other target but itself would be weird. Then private GetComponent makes way more sense.

    I don't care about the performance difference... it's negligible in the grand scheme of things (of course there may be edge cases where it might pop up its head... but for general audiences it doesn't matter). And I think that's @Kurt-Dekker's point... don't worry about these micro-optimizations. Rather...

    The intent... don't muddy it.
     
  11. ricardoCoelho

    ricardoCoelho

    Joined:
    Jul 6, 2020
    Posts:
    18
    Thanks for your reply @lordofduct, this was what I was looking for.
    My question was never to make micro-optimizations, but to find the 'standard' way of doing things with Unity.
    I never used ' void Start() => GetComponent() ' before and allways dragged in from the inspector, but will start to include it now and try to make them only public when they need to accessed from external classes.