- Home /
Does the access modifier of Start(), Awake(), OnEnable() make a difference to Unity?
Does it make any difference to Unity if I use public void OnEnable() vs private void OnEnable()?
Is there a general practice you can recommend? When subclassing MonoBehaviours it probably makes sense to use protected or even protected virtual. However, I often see thoses methods being exposed publicly. This only spoils my auto-completion, since I won't ever call those methods explicitly, right? Or is there a performance benefit because Unity searches faster for public methods?
Thanks!
Answer by valyard · Sep 05, 2015 at 07:53 PM
While @BMayne is mostly correct, it's worth noting that Unity doesn't use reflection nor to get these functions nor to execute them at runtime. Since it uses Mono virtual machine, Unity from C++ code can ask it what methods a class has.
So internal logic is like this:
Get all methods from the whole class hierarchy down to UnityEngine.Object.
Filter instance methods.
Find built-in methods like Awake, Start, Update, etc... and put them in a cache.
For all instances of a class add pointers to their Awake, Start, Update, etc... methods to corresponding managers which call these methods when needed.
Usually you don't want these methods public, having them non-public doesn't matter performance wise. You can have these methods protected though if you want to set up an inheritance chain.
But in this case you must be really sure what you are doing, since if you have for example a custom MyMonoBehaviour
class derived from MonoBehaviour
with all these methods (Awake, Start, Update, etc...) declared as protected virtual
, ALL these methods for ALL instances of classes derived from it will be registered with aforementioned managers internally and be called each frame (in this case I'm talking about Update). Though individually these empty methods are fast, having hundreds of them may slow things down.
I the public/private question isn't applicable in actual technical sense, due to the way these methods accessed in a special way from within the runtime.
However, I'm torn about whether Awake etc. "should" be public from a style/philosophical point of view.
The fact is, the methods are being called from outside the class hierarchy -- that's the common sense definition of public, right?
Curious what you think about this stylistic/philosophical point?
Well, that purely depends on how you declare the methods from an OOP point of view. For example if you declare your methods as non virtual methods there's no point in using any access modifier than private. The methods are only relevant to the class itself since they are called only directly from the runtime.
However if you want to use some inheritance / base classes you might want to declare them as virtual. In that case "protected" would be appropriate. "public" is actually never appropriate since those methods are never ment to be called manually from another class.
Sure, but private or even protected doesn't feel right (again, just stylistically/philosophically speaking) because those aren't meant to be called by the runtime either, really. Unity's runtime basically breaks the semantics of private/protected here. That's why I wonder if public is actually closer to the spirit of what's actually happening. These methods ARE going to be accessed outside of the class -- i.e. by Unity's runtime (albeit via a completely different mechanism nothing to do with public/private/protected).
Clearly the correct style is to just write void Start()
, with no explicit access modifier. Because that's the way Unity does it. I$$anonymous$$HO, that's the definition of Style.
If you start writing void public Start()
, or even the redundant void private Start()
, it will stand out -- people will waste time wondering why you had to change it from the usual way.
I agree this is Unity's style. What I'm really asking is if Unity's style is really "right". I've always followed it. But I do suspect it wasn't really a good style choice by Unity for the reasons noted.
No, those methods aren't accessed from outside the class. $$anonymous$$eep in $$anonymous$$d that a $$anonymous$$onoBehaviour component consists of a native and a managed part. You only see / edit the managed part. The native and manage part of the class are communicating in both directions. For example when you read the position property of the Transform class you actually call a hidden external method in the native part of the class which returns the position which is also stored in the native part.
The callback methods like Start, Awake, Update, ... are actually callbacks which are called from the native C++ side.
Some people try to view their scripts as plain C# but Unity is't written in C#. $$anonymous$$ono is just the used scripting engine. When you design components you should focus on the usage within it's domain inside Unity. As such you never want to directly call those methods from another class. They are simply callback methods from the engine and only relevant to the class itself.
If someone else is using your class as a blackbox they shouldn't see those methods since they belong to the component itself. You could imagine them like you implicitly registered them to some kind of manager. So just like there's a line like this in the constructor:
manager.RegisterStartCallback(Start);
In such a case you would make Start private since it's only used internally by the class itself. Based on basic OOP encapsulation rules those methods should be private. $$anonymous$$aking something private / protected / public has nothing to do with a "style". The decision should be only based on the usage of those things. A style is a different way of structuring code without actually changing anything. Things like where you place your opening brackets, how you split long lines, na$$anonymous$$g conventions, in which cases you use "switch" ins$$anonymous$$d of "else if", when you use while / for / do-while ...
I see it differently. Sure, they are being called from the C++ side, that's not the question. The question is whether that call from Unity's game loop is closer to the "outside" or "inside" semantics. Seems closer to outside to me.
Answer by BMayne · Sep 04, 2015 at 05:13 PM
Hey there,
Here is an example of what Unity is most likely doing behind the scenes.
typeof(MonoBehaviour).GetField("Start", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
As you can see it searches for the function by name and then if it is public or non public (internal, protected, or private). When you change the access modifier it will have no effect on Unity's ability to grab it.
Cheers,
Answer by Owen-Reynolds · Sep 04, 2015 at 04:48 PM
I'm going to guess it won't matter, but check whether any of this is wrong:
I assumed C# had some bizarre rule where, maybe a superclass or something could have subclasses default to public or something. But, of course, no. Start is private, and is being found using Reflection. That a known trick (why!?)
I think Reflection can specify only finding Private or Public members, which probably runs faster. But Unity isn't doing that. public Start()
works just fine. There doesn't seem to be any other way to use Reflection besides "limit to only these sorts of things."
And, Reflection still gets a reference, right? It's not like it's doing it every frame for Update. I'm wondering if it doesn't do it once for each class, even, not each instance in the class. So the whole thing is just a minimal amount of work at start-up (maybe Instantiate, maybe not.) So falls under the usual "don't bother -- can't possibly save enough to matter" optimization rule.