Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding getters/setters in gdscript #8045

Open
TranquilMarmot opened this issue Oct 9, 2023 · 6 comments
Open

Allow overriding getters/setters in gdscript #8045

TranquilMarmot opened this issue Oct 9, 2023 · 6 comments

Comments

@TranquilMarmot
Copy link

Describe the project you are working on

Setting a class's ID/type using a setter causes it to grab extra info and do calculations. Some subclasses need to grab info from a different place and do different calculations.

Describe the problem or limitation you are having in your project

Let's say I have two classes.

A parent class:

class_name ParentClass

var my_value: String:
    set(new_my_value):
        my_value = new_my_value

        # do some stuff...

And a child class:

class_name ChildClass
extends ParentClass

var my_value: String
    set(new_my_value):
        super(new_my_value)

        # do even more stuff...

Currently, this will result in an error:

The member "my_value" already exists in parent class ParentClass.

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

It would be nice to detect when a member has a getter/setter and allow overriding it, with the ability to call super to call the base class's implementation.

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

When there is a set/get on a member, allow overriding it. Otherwise, still throw the "The member ___ already exists in parent class ____" error.

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

The easiest workaround is to just define a function.

Parent class:

class_name ParentClass

var my_value: String

func set_my_value(new_my_value: String):
    my_value = new_my_value

    # do some stuff...

Child class:

class_name ChildClass
extends ParentClass

func set_my_value(new_my_value: String):
    super(new_my_value)

    # do even more stuff...

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

Would not be possible if not a core feature.

@dalexeev
Copy link
Member

dalexeev commented Oct 9, 2023

This is not possible with inline setters/getters, but you can do it with separated setters/getters:

class A:
    var x: set = set_x
    func set_x(value):
        prints("A", value)

class B extends A:
    func set_x(value):
        prints("B", value)

func _ready():
    var b = B.new()
    b.x = "test" # Prints "B test".

@Mickeon
Copy link

Mickeon commented Oct 9, 2023

I think an all-encompassing annotation could be nice for this. Of course, you shouldn't be allowed to change the type of the property. But everything else, such as the way it is exported, and the initialised value sound like fair game, to me. There are workarounds to make this work, but they can get somewhat verbose sometimes.

@TranquilMarmot
Copy link
Author

Setting a separate function as a setter/getter is clever! I wonder if it would be helpful to have as an example in the docs somewhere 🤔

@moritztim
Copy link

moritztim commented Nov 16, 2023

This is not possible with inline setters/getters, but you can do it with separated setters/getters:
It doesn't seem to be possible with static vars:

# Control.gd
extends Control

static var bruh:
	get:
		print("hi")
		return null

func _init():
	print(bruh)
#Control2.gd
extends "res://Control.gd"

func get_bruh():
	print("ho")
	return null

func _init():
	print(bruh)

image

@dalexeev
Copy link
Member

dalexeev commented Nov 17, 2023

@moritz-t-w You used inline getter in the base class, so get_bruh() in the inherited class is just a function, not a getter. You also cannot combine static variables and non-static setters/getters (or vice versa), although there is currently a bug, it does not raise an error.

This code should work:

# Control.gd
extends Control

var bruh:
    get = get_bruh

func get_bruh():
    print("hi")
    return null

func _init():
    print(bruh)
# Control2.gd
extends "res://Control.gd"

func get_bruh():
    print("ho")
    return null

func _init():
    print(bruh)

It doesn't seem to be possible with static vars

Regarding static variable setters/getters, this may indeed not work since static functions have inconsistent behavior, they are not fully virtual. Essentially, you are not overriding a static function, but simply shadowing it with a function of the same name, from which you can call the parent method using super(). This is late static binding problem, see godotengine/godot#72973 for more details.

@moritztim
Copy link

Oops, thanks for the correction!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants