Using set("var",val) calls setter methods even when within the class.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By tx350z

I’m not sure if this is “as designed” or a bug so I’m asking here.

When calling the set() method to set the value of a variable with a setter method, the setter method is called even when set() is called within the class as the variable. For example, the following will cause __prop() to be called.

var prop:int setget __prop;
func __prop(_value:int):
    prop = _value;

func _ready():
:bust_in_silhouette: Reply From: rossunger

This seems normal to me? is there any reason you wouldn’t want it to work like this?

I have some vague memory of reading about set() not getting called unless you use self.set()… but I don’t remember the details of that…

I have a need where certain property values are allowed only when set from within the class. The only way I can see to do this is to apply constraints in setter methods. This works well enough.

However, I’m also serializing/deserializing the properties using json files. Deserializing is easiest if I can loop on key names and just do set(“key”,“value”). This is where I run into the problem of deserializing constrained values because the setter is called even though I’m calling set() within the class.

The work-around is a massive match statement where every property is explicitly coded. It works but is difficult to maintain.

And yes, I know about inst2dict/dict2inst. The problem there is it isn’t recursive, doesn’t handle objects, and, in some of my use cases, includes properties that I don’t want included in the serialization.

For now, I’ll assume the behavior is working as intended and not an engine bug.

tx350z | 2022-02-06 11:20

if you’re setting an object’s variables from another objects script that kinda an anti-design-pattern… are you familiar with these? :
Design Patterns

It seems like you’re trying to achieve a private/public kinda thing where certain properties are only editable by the object itself…

If i understand correctly, you’re tying to call “set” on this object from a script attached to another object?

In this case, you might consider structuring it like this:


myObject.doTheSetting(property, value, self)

and in (the object where you’re setting):

func doTheSetting(prop, value, who = self):
if who == self:
	set(prop, value)
	if not prop in ["firstPropNotAllowe", "SecondPropNotAllowed", "etc" ]:

Or if there’s more properties that are not allowed than allowed, then you just invert that last if statement, and put the set fuction inside that if block

rossunger | 2022-02-06 12:51

Thanks for the suggestions. I’ve resolved myself to the fact that it is unlikely GDScript will ever support private properties. Note that one of your suggestions produces a “silent failure”.

When a property has a setter, the setter is not called from within the class unless the property is prefixed by “self”. So my specific question is if set(“var_name”,“prop_value”) called from within the class should behave the same way?

In other words, should set(“aprop”,1) and self.set(“aprop”,1) behave the same?

var aprop:int setget __aprop;
func __aprop(_value:int):
    aprop = value;

func _ready():
    aprop = 1; # Does not call setter method -- expected
    self.aprop = 1; # Calls setter method -- expected

    set("aprop",1); # Calls setter method -- unexpected, bug or not?
    self.set("aprop",1); # Calls setter method -- expected

tx350z | 2022-02-06 14:53