+1 vote

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);
Godot version 3.4.1.stable.official
in Engine by (70 points)
edited by

1 Answer

0 votes

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...

by (1,260 points)

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.

if you're setting an object's variables from another objects script that kinda an anti-design-pattern... are you familiar with these? :
https://refactoring.guru/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

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("varname","propvalue") 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
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.