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():
    set("prop",12);
: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:

in OtherObject.gd:

myObject.doTheSetting(property, value, self)

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

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

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