Have you discussed internally how to improve this? I mean when your released tu new UI System you where smart enough to do it the right way, with interfaces. So if you want to “listen” to clicks you do this:
class Test : IPointerClickHandler {
public void OnPointerClick(PointerEventData eventData) {}
}
But what about MonoBehaviour (and not only MonoBehaviour) messages that are sent “magically”? Have you discussed to do it similarly?
class Test : IAwake, IStart {
public void Awake() {}
public void Start() {}
}
Apart from performance perspective or that it’s not the best way to do it I have the following problem testing the code quality: Log in with Atlassian account
Also making unit testing you can’t call directly this methods and you need to do it via reflection.
I Know that it’s not a easy matter because you should do it via API Updater carefully do developers that don’t want to upgrade their code (or can’t like asset store old packages) manually can do it automatically.
we have interesting plans to improve the whole MonoBehaviour and messages story.
We are experimenting with a few approaches atm, but it will take a bit of time because there are a million things to consider to make sure we are solid enough. The interface-based approach you described above is one of the most promising we are considering.
We will share more the closer we get with something concrete.
Personally I really hope unity drops all the magic and just goes with virtual methods. That is how C# intends this to work - other approaches will always be fighting the language in some way.
Interfaces would be a lot better than current MonoBehaviours, but still it makes for all of these awkward designs:
Common use is to make a behavior intended as some base class. Now you’d still want to frequently mark the used callbacks as virtual anyway - so we’d still be stuck with callbacks sometimes being virtual, sometimes not.
These interfaces could only be used on ScriptableBehaviours. So now there needs to be a validation layer to check your code and make sure you’re using the interface right etc. That really should just be handled by the compiler
ScriptableObject (or whatever the new variant would be) only supports a subset of callbacks so it’d be able to eg use IEnable, but not IUpdate. Again this would require validation of the code, custom errors after compiling, documentation for the users etc. For base functions this would all just be immediately obvious - compiling code is valid code.
What happens if users would use public void IAwake.Awake() - now the function is hidden, so there’d still be inconsistent access patterns. This could mean unity would still have to call these new methods with slow and bulky reflection magic vs finally just being able to efficiently do one virtual call for them.
Functions are now ‘declared’ in two places, in the type & the in body. More hassle, redundant code, redundant typing.
You would still not get any discoverability on what functions are available (for base functions just write override and you’d get a list)
I don’t think type declarations like class MyScript : ScriptableBehaviour, IAwake, IEnable, IDisable, IUpdate, IFixedUpdate, IDestroy etc. will be very managable or very nice…
It conflates type with functionality. Eg, GetComponent() should work then but that’s just jibberish. public void Test(IAwake someObj) ? Not a huge deal but still - compilable code should strife to be valid code.
It would force all callbacks to be public. I think it would be nicer if all of these were protected.
To any newcomers with a programming background it will just be more weird black box magic. Programmers do understand what base functions are though.
Just regular virtual functions seem much cleaner, but I’m sure I’m missing some concerns. Maybe it would be quite a lot of virtual functions to have on a behaviour, but I really hope at least the ‘basic’ functions could be regular virtuals, and only have infrequently used functions hidden behind an interface.
Can’t wait to hear more about the ScriptableObject stuff though!
Won’t this degrade performance a lot when you do GetComponent ?
It would have to look at every component, and then at every interface it implements, …
Or is that not a problem at all?
I agree that an empty virtual implementation in a base class + override in your own MonoBehviour is a bad idea!
Unity would then call Update on EVERY gameobject, even if it doesn’t need Update().
Sure, its empty calls, but it happens every frame. And I don’t know about you guys but I like to use transforms as “folders” to keep things organized, and also to have a common parent that I can move/rotate/scale. That’s important and I wouldn’t want Unity to call Update for all the folders for no reason at all
Most of the time you do only want 2 or 3, and so you’d only override 2 or 3. No need to override all of them, you wouldn’t see this base class. It’s really not the same as these accessors - just having the basic functions as virtuals wouldn’t couple ScriptableObject with other code. Point take that maybe eg collisions callbacks would - but see other point about how infrequently used functions could still work as an interface
Yes the same problem exists, so let’s fix it.
Again, let’s fix it. Just having defaults won’t help that much - fundamentally we still have split functions into two, no way around that, I don’t think Start and Awake cover that many cases.
Reading the docs is more work than intellisense Yes, uGUI has the same problem. I care about it, sucks having to google stuff ever time, there is an obvious solution to fix that in this case.
So… why not mark them as virtual functions in the unity base class and standardize that?
Fair point, so let’s exclude stuff with arguments or that could pull in other sub systems in some way (physics, networking callbacks etc.). No reason to do that for Update, Enable, Disable, Reset, Destroy, Awake, FixedUpdate, render callbacks etc. etc. though, there are really no coupling issues there.
@dadude123 : This really is not a concern - or well, it is, but if you think this is bad - the current state is HORRENDOUS. We (Ori and the Blind Forest) have had lots of fights with how slow messages are at the moment, the Playdead guys (Inside) were talking about it and recommend avoiding them altogether, I hear more devs complaining about it, hell even unity knows it: Unity Blog.
Their current way of doing update calls is horrendously awful. Finally having standardized, compiler validated, virtuals would mean they could cut these costs waaay down. If it still turns out to be an issue, nothing is stopping them from not calling the function if it’s not overriden anyway.
Could you tell me how many scripts / objects you had in the average scene?
What did you do to circumvent the problem? Surely you didn’t roll your own update scheduler for every single script you made, right?
Or are you talking about SendMessage() ?? (which is something completely different!)
Now, are you sure that it would make much of a difference between how things are right now, VS making interfaces?
Surely every call has overhead (and virtual calls even more so!). So I’m not that convinced that the change from what unity is doing now to using interfaces or empty virtual method bodies in MonoBehaviour would make much of a difference.
The best way to do it is to just not call at all!! Unity could easily check what scripts need Update() and put them into List ThingsThatNeedUpdateCalls; (or just make it a List in the first place, then remove them from the list when they get inactive or whatever).
Keep in mind I’m not saying the performance improvement won’t be big enough, I’m asking.
We had couple thousand upward to 10K scripts in a scene.
We did avoid Update at all costs and had some Update managers for that, but we did use ‘regular’ OnEnable / Awake calls. Those were optimised to be super light weight, but just CALLING those took >15ms, causing a spike, which as the game is totally streamed and scenes are loaded quite often was really bad.
SendMessage(), ironically, only appears to be a little different. From my measurments it’s slower than OnEnable() yes, but not even that much slower.
So yes I’m sure that doing a straight virtual call is WAY faster that what we have now. If you read the blog post you can see the insane amount of stuff unity is doing. A virtual is ‘slow’ because of one pointer dereference… I think unity easily might be doing two orders of magnitudes more than that currently.
If all of this sounds insane it’s because it is - I really can’t stress how slow callbacks are at the moment. Most developers of bigger games just recommend avoiding them as much possible altogether - kind of a shame for something so basic
I agree that unity should keep a list of what does and doesn’t need to be udpated - but that’s independent of whether they go with virtuals or interfaces.
Without going into details about ScriptBehaviour - because I don’t know the details of exactly what the Scripting team are working on - I wanted to respond to a couple of points in this thread:
While that’s true up to a point, what if we have heard from users that there are downsides to the way Unity UI is designed? Surely we should not just ignore that feedback? (The right answer here is most likely ‘you should fix those downsides in Unity UI as well’ )
No, it wouldn’t - that would indeed be a bad idea. When we are looking for Update methods to call, we’d check which class they’re actually defined on, and we would skip calling it for objects that didn’t override ScriptBehaviour.Update().
Bear in mind that while a base class full of virtuals would make it easier for coders to discover which methods they could implement, it would make it harder for code to discover which methods have been implemented. Instead of being able to do “someObj is IUpdateable” you’d have to use reflection and stuff. It’s a tradeoff that might be worth it, but it’s still a tradeoff.
Neither interfaces nor virtual functions would have any impact on the cost of Update() callbacks. We do all the work to find the magic methods (and check their signatures, etc) once per class, at startup; the cost of actually calling something like Update() is entirely in the actual transition from native to managed code. Switching to interfaces or virtuals might help a little with the cost of the former, but it wouldn’t affect the latter.
Thanks for the answers guys, really clarified things for me.
But can that even be optimized more at all?
Isn’t the whole point of this to improve performance? So why switch to interfaces or virtual methods at all then? Just for readability or to make it more clear for newcomers?
Yeah, the new ScriptBehaviour is mostly not about performance, but about improving design and usability. (Naturally if there are opportunities to improve performance in the process then we’ll take them, but it’s not the #1 goal).
I hope that finally you guys will remove the deprecated properties from MonoBehaviour: “rigidbody” “collider” etc.
They’re really nice names to use, and Unity complains that I need to add “new” “property name” while in the editor, but then complains I don’t need “new” when doing a build.
cdf: agreed, I wonder when that and other deprecated functions will get removed
Hmm thats sad. Because people will eventually get used to a somewhat strange design.
But they can’t get used to bad performance. Having to write your own update scheduler(s) is a constant pain point which is really not optimal or even expected.
Not sure why you guys are working on something that will (at best) only confuse people a bit because things change, as opposed to something people directly profit from
But then again I don’t know how closely those two problems are really related, I don’t know how the code works, and I’m hopeful that the .net/mono upgrade will produce or enable some performance improvements along the way
No offense though!! I completely understand that the current situation is not optimal and why you want to fix it. Just my thoughts on this.
I wouldn’t worry too much. There are other things in the pipeline that will have a far bigger impact on the way you structure high-performance code than whether our MonoBehaviour-replacement uses interfaces or virtuals
Oh, that’s great to hear!
Any hints or sneak peeks what we could possibly expect?
I don’t want to derail this thread tho. Feel free to PM me if you have some details or even vague hints or ideas