godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

Implement partial classes #2410

Closed me2beats closed 3 years ago

me2beats commented 3 years ago

Describe the project you are working on

Plugins

Describe the problem or limitation you are having in your project

I want to create classes (scripts), the extension of which does not require changes to the script file.

By extension I mean adding new methods, properties signals and classes.

This is useful in different cases:

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Implementing partial classes would solve the problems.

I hope this approach as relatively easy to implement, It is also quite intuitive and requires minimal setting up from the user - he just creates a new script and specifies in it that it is an extension of the class X

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

This is an example of how it could look like

x1.gd:

partial class_name X

var num = 1

func a():
    print('a')

x2.gd:

partial class_name X

func b():
    print('b')

This means X has num property and also a and b methods.

If this enhancement will not be used often, can it be worked around with a few lines of script?

There is no way to add new properties and methods without changing the script itself. Partial classes could solve it.

Is there a reason why this should be core and not an add-on in the asset library?

I don't think it could be done using an addon.

dalexeev commented 3 years ago

In other words, you are proposing to make it possible to declare a named class in multiple files. But isn't it easier to add the ability to (statically) include the file? Then this feature will also be available in unnamed classes. There is a proposal for include/import.

# x1.gd:
class_name X

include 'x2.gd'

var num = 1

func a():
    print('a')

# x2.gd:
func b():
    print('b')
me2beats commented 3 years ago

@dalexeev this is similar, but different. When using include/import in X, you still have to change X each time when you want a new file to be included.

dalexeev commented 3 years ago

Yes, but on the other hand:

  1. by opening x1.gd you will immediately see all the files in which this class is defined; you don't need to guess if there is still a file that has partial class X (explicit is better than implicit);
  2. you will be able to include 'x2.gd' also in Y, Z classes i.e. reuse the code (some kind of mixins); this is not possible with your proposal;
  3. as I wrote above, include can be used in unnamed classes as well, unlike your suggestion.

And can you give me a real example where you need to split a class into several files? I do not find this feature useful (neither your suggestion nor include), except for the possibility of reusing the code (point 2).

me2beats commented 3 years ago

Partial classes are used in several modern and advanced languages, for example in C#

They can make teamwork happier. They are also useful for code generation.

Partial classes don't provide code reuse by themselves, that's true. But they don't limit you to use any other approach for reusing the code.

I have no idea yet how to make them work with unnamed scripts; is that a problem tho? Just make the class named:)

If the question is what to choose: partial classes or include, I don't see a problem here — they both could exist in gdscript and complement each other

vnen commented 3 years ago

I have no idea yet how to make them work with unnamed scripts; is that a problem tho? Just make the class named:)

Considering that named classes go into the global scope, some users prefer to restrain the use of named classes. Although in this particular situation I wouldn't mind requiring this. It does make the feature less flexible.

If the question is what to choose: partial classes or include, I don't see a problem here — they both could exist in gdscript and complement each other

Honestly, I don't to bring everything and the kitchen sink into GDScript. I prefer adding one solution that brings benefit to most users.

My intention is to eventually implement "traits", which works much like an include (but can also work as an interface). I still need to write a proposal for that, hopefully I can put something up soon. This would solve the re-usability part which is indeed a problem of the current system. I believe that would solve most of your points.

I don't really see the usefulness in this. If splitting code into multiple files is needed, you may want to reconsider your class (or potentially use the traits in the future). Same thing for moving across projects. Also, not sure why you don't want to change a particular file for refactoring, a VCS should help you getting back to a working version without losing your work, and if you're only adding functions I'm not sure what would break. Regarding conflicts between team members, it's really only a problem if multiple people are changing the same code which wouldn't be solved by this anyway since people would be working on the same functions and couldn't use the partial class feature. So it seems quite limited to warrant the addition.

It does have downsides too. If you inadvertently make two unrelated files part of the same partial class, it can lead to pretty confusing situations. Especially on a team setting where people are working in different areas but might be using the same partial class name without realizing. Reading code is also hindered because you see a "partial class" and then you have to fishing for the other parts (that may not even exist) in order to understand the whole class.


From the technical point, there's the main problem that one file is one resource in Godot, and as such using a partial class file as the script resource will lead to inconsistencies. If you have part in a.gd and other part in b.gd and you use both in different nodes, it's quite difficult to correlate that they are indeed the same script. Using load("a.gd") needs to be the same as load("b.gd") which is not great, nor really user-friendly.

All in all, my assessment is that the cons outweigh the pros in this case (also considering that traits should solve most of code-sharing issues).

me2beats commented 3 years ago

Сlosing it due to the limitations and lack of consistency in relation to GDScript and in favor of more flexible solutions such as traits.