godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.14k stars 93 forks source link

Allow using interface as exported property type #307

Open mysticfall opened 4 years ago

mysticfall commented 4 years ago

Describe the project you are working on: The issue may be relevant to any C# project.

Describe the problem or limitation you are having in your project: For now, Godot allows defining an exported property of Array<T> or IEnumerable<T>, provided T is one of the types that Godot knows how to serialize.

However, sometimes you may need to store different subtypes of type T in IEnumerable<T> which in turn may define a type parameter itself.

For instance, let's say we want to create a character customization system and we allow our users to morph either the color or bone scale of their characters.

Naturally, a C# programmer would define a parent type like Morph<T> : Resource and declare derivative morphs as something like ColorMorph : Morph<Color> and BoneMorph<float>, respectively.

However, if you want to make them as resources and assign to an exported property, it becomes problematic.

As C# does not have a concept of wildcard type parameter, we can't declare such a property as [Export] IEnumerable<Morph<_>> Morphs { get; }.

Normally, a common remedy to the problem is to define an interface IMorph which each morph implementation may implement. But Godot currently does not support using an interface type in a signature of exported properties.

One may try to circumvent the problem by using an abstract class instead like this:

public abstract class Morph : Resource { ... }

public abstract class Morph<T> : Morph { ... }

However, it's not always possible to do so when type hierarchy is more complex, so we have to use the lowest common denominator approach, and use IEnumerable<Resource> instead.

And of course, it means we can't have any type validation when we drag resources over such fields which is not an ideal solution.

Describe how this feature / enhancement will help you overcome this problem or limitation: If Godot allowed using an interface type as T in IEnumerable<T> or Array<T> for exported properties, it would solve the problem explained above.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:

Describe implementation detail for your proposal (in code), if possible:

If this enhancement will not be used often, can it be worked around with a few lines of script?: I mentioned a possible workaround above but it's not an ideal solution.

Is there a reason why this should be core and not an add-on in the asset library?: I don't think it's something easily implemented by an add-on.

I understand that it may be a low priority issue which may not be easy to solve. But this is a pattern of problem I've encountered a lot when I tried to migrate my project to use custom resources, so I wanted this feature request to keep track of relevant discussions in future.

MochaMoth commented 1 year ago

I'm coming from Unity, and there is a package known as Odin Serialization. This adds a drop down to any interface reference in the editor that allows the designer to select which implementation to use, then draws the public parameters for that implementation just below. IMO this addon is essential to working in Unity because interfaces are integral to development with C#. All of my tools depend on Odin and I'm able to create great separation between components while opening the door for anyone to extend any part of the system without needing to access source.

I'm currently in the process of porting over all of my packages to Godot and I'm finding that I won't be able to use this plug-in style architecture at the moment. I know Godot is currently collecting opinions from Unity devs for reasons, so this is just my two cents. Would greatly improve the development process if interfaces could be serialized in the editor.

PereViader commented 1 year ago

I also think interface serialization is an integral part of my development workflow. When developing in Unity, instead of using Odin, I rely on a variation of this: https://github.com/Guillemsc/ImplementationSelector

I opened a discussion to try to revive this topic https://github.com/godotengine/godot-proposals/discussions/7971