After months of implementing a scripting framework in a ground-up automation suite, this week I switched gears and did a major refactor that put all scripts into a single scope (per plugin, anyway… eventually, I may be able to consolidate those into a single scope as well).
It was a complete paradigm shift, learning how to more elegantly facilitate interopping. I came to a rude awakening about how much serialization has to be done to marshal objects across languages. Eventually, though, I realized there are some hard limits in terms of what can be done with the “scripting” language in ways that will allow objects to be usable with the base language (loss of generics is a big one). You can hack things in… but only with more serialization in the script language, and parsing the hack, and reconstituting the intended object in the base. Of course, this extra serialization comes with a performance hit. Usually unnoticeable.
(Note: Below is all conjecture… I don’t actually know how the Unity team chose to go about their own interop, I’m just making a lot of assumptions based on my own experience)
Anyway, this gave me some ideas as to how Unity might have implemented its own interopping scheme, and I got a full brain-cascade of “Oh wow, that’s probably why they did it that way.” It used to boggle my mind why I couldn’t do certain things that are normally allowable in C# with Unity. Now I see there probably weren’t many options at the time (or at least none that would allow them to hit whatever milestones they may have had).
Technically, you have full use of the C# interpreter. All the functionality is there. You only start bumping into things when you try to hand those objects back to the base Unity engine. You can morph your objects any way you like within the C# interpreter at runtime, but only as long as those objects are still being handled by the interpretter. Once you need to feed those objects back to Unity, it has to be done in a way that .NET can serialize and then deserialize across scopes (at least in my own experience).
This could be why you can’t feed Unity objects that have generic implementations (at least, for now). Theoretically, if your type parameters had a very narrow, hard-defined scope, you could, because all the possible implementation details could also be passed during serialization. But then you wouldn’t really have a generic class, would you? It’d just be run-of-the-mill polymorphism with an overcomplicated interface.
In any case, now that I’ve got a good idea of how Unity’s engine may actually be utilizing C#, and I’ve learned a great deal about how to develop scripting frameworks for interop, I suddenly find myself with renewed interest in Unreal. I think about what they’re doing with Blueprint, and get some ideas about how it could be leveraged with careful extension of the base engine. It effectively becomes a limited form of interop of its own. I don’t think it technically is, but the approach might be the same.
I could see some really clever things being done there.