I need to be able to access the class script from inside a static method, in order to support multiple constructors for my classes. I need this very badly, otherwise I am gonna have to rewrite most of my application. What I am looking for is something similar to the python @classmethod, where the class gets passed as an argument allowing you to return an instance of it. Unfortunately, there seems to be no way to access the class script from inside a static method in godot. What could be other solutions?

  • Instead of a single class, you can move the static functions into a second class. That way the cyclic dependency doesn't happen on the MyClass.new() because it's technically not in MyClass.

    For example:
    File 1:

    extends Reference
    
    class_name MyClass
    
    var x: float = 0
    
    func _init(x_val):
    	x = x_val

    File 2:

    extends Reference
    
    class_name MyClassFrom
    
    static func sum(a,b):
    	return MyClass.new(a+b)
    
    static func product(a,b):
    	return MyClass.new(a*b)

    File 3:

    extends Node2D
    
    func _process(delta):
    	var a = MyClassFrom.product(2,3)
    	print(a.x)

Can you be more specific about what you are trying to do? Is this for a factory type of class?

    When I need multiple constructors, I usually just pass different arguments. Sometimes I pass a dictionary and parse out what the _init() method needs. It sounds like you're trying to do it the hard way.

    So, I think you might be right, @duane . It seems the OP wants this:

    var obj = Factory.create(MyClass)

    Which is don't believe is possible, but let me check. However, if you already know the class name, you can do this, which is less code and more clear:

    var obj = MyClass.new()

    cybereality What I need is to be able to implement one or more static methods in a class that return a class instance itself. For example:

    extends Reference
    class_name MyClass
    
    var x: float = 0
    
    func _init(x_val):
        x = x_val
    
    static func from_sum(a, b) -> MyClass:
         return MyClass.new(a+b)
    
    static func from_product(a, b) -> MyClass:
         return MyClass.new(a*b)

    This way I should be able to use MyClass.from_sum and MyClass.from_product as two different initializers. This code doesn't work in godot, because I am referencing MyClass from within its script, and the compiler gets mad (Although there is no actual reason for it)

    As far as I can tell, you can't use the same class name inside the class itself. It's a cyclic reference in GDScript.

    You're thinking in terms of compiled languages. Gdscript isn't designed to work like that. This is the most appropriate way to do it:

    extends Reference
    class_name MyClass
    
    
    enum {
    	MY_CLASS_FROM_X,
    	MY_CLASS_FROM_SUM,
    	MY_CLASS_FROM_PRODUCT,
    	}
    
    
    var x: float = 0
    
    
    func _init(how:int, val1, val2=null):
    	if how == MY_CLASS_FROM_SUM:
    		x = val1 + val2
    	elif how == MY_CLASS_FROM_PRODUCT:
    		x = val1 * val2
    	else:
    		x = val1

    # main.gd
    extends Node2D
    
    
    func _ready():
    	var m = MyClass.new(MyClass.MY_CLASS_FROM_X, 10)
    	print(m.x)
    	m = MyClass.new(MyClass.MY_CLASS_FROM_SUM, 10, 5)
    	print(m.x)
    	m = MyClass.new(MyClass.MY_CLASS_FROM_PRODUCT, 10, 5)
    	print(m.x)
    	pass

    Maybe you should try C# instead.

    Instead of a single class, you can move the static functions into a second class. That way the cyclic dependency doesn't happen on the MyClass.new() because it's technically not in MyClass.

    For example:
    File 1:

    extends Reference
    
    class_name MyClass
    
    var x: float = 0
    
    func _init(x_val):
    	x = x_val

    File 2:

    extends Reference
    
    class_name MyClassFrom
    
    static func sum(a,b):
    	return MyClass.new(a+b)
    
    static func product(a,b):
    	return MyClass.new(a*b)

    File 3:

    extends Node2D
    
    func _process(delta):
    	var a = MyClassFrom.product(2,3)
    	print(a.x)

    If you don't mind it being a little hacky, you can put the generator in the same class. Note that you have to use an existing object to make the rest of the objects -- the reference doesn't exist until it's instantiated.

    extends Reference
    class_name MyClass
    
    
    var x: float = 0
    var ref = get_script()
    
    
    func _new(i:float):
    	var n = ref.new()
    	n.x = i
    	return n
    
    
    func from_sum(i:float, j:float):
    	var n = ref.new()
    	n.x = i + j
    	return n
    
    
    func from_product(i:float, j:float):
    	var n = ref.new()
    	n.x = i * j
    	return n

    extends Node2D
    
    
    func _ready():
    	var my_class_generator = MyClass.new()
    
    	var m = my_class_generator._new(10)
    	print(m.x)
    	m = my_class_generator.from_sum(10, 5)
    	print(m.x)
    	m = my_class_generator.from_product(10, 5)
    	print(m.x)
    	pass

    Or even... 🙂

    extends Node2D
    
    
    func _ready():
    	var m1 = MyClass.new()._new(10)
    	var m2 = MyClass.new().from_sum(10, 5)
    	var m3 = MyClass.new().from_product(10, 5)
    	print(m1.x)
    	print(m2.x)
    	print(m3.x)
    	pass

    @Kojack solution is better, because it uses static functions. Otherwise you need to create a new generator object every time you need another object, which is unneeded overheard. Plus, if you are already calling new(), you might was well call new() on the object you want.