Godot version:
3.1 beta 2
OS/device including version:
Windows
Issue description:
As suggested in the title, having a script not be able to use its own Class name in its own script is severely limiting. For instance, one could not make any factory methods or methods that make more of the class. I came across this limitation when trying to make a 'Set' class. Trying to use the identifier Set
results in an error: Parser Error: Using own name in class file is not allowed (creates a cyclic reference)
extends Reference
class_name Set
# with static typing
# this line causes an error
func union(other: Set) -> Set:
# this line also causes an error
var result = Set.new()
# do stuff
return result
# even without static typing
func intersection(other):
# we can't even do this
var result = Set.new()
# do stuff
return result
func copy():
return Set.new(my_items)
Temporary Workaround
I found a way to do what I want here, but it feels inelegant and renaming the script or moving it becomes a hassle.
extends Reference
class_name Set
var Self = load("res://set.gd") # set.gd is the name of this very script
func union(other):
var result = Self.new()
# do stuff
return result
func intersection(other):
var result = Self.new()
# do stuff
return result
func copy():
return Self.new(my_items)
but this still disallows me from using static typing since I can't then use Self
as a valid type
Seems like a duplicate of #21461..
UPDATE: It seems as of 3.1 beta 3, this is now allowed
class_name MyClass
func test(instance: MyClass) -> MyClass:
return instance
Thank you to whoever worked on this issue! It really helps a lot.
However I cannot close this yet as the following is still not allowed
class_name MyClass
var id: int
func _init(n: int):
id = n
func clone() -> MyClass:
return MyClass.new(id) # still causes the cyclic dependency error
Mmm, I ran into this issue too. Need to check if a nodes parent is the same class as it, but can't. Be nice to see it patched out soon. :/
I found a work around by overriding get_class to give the right answer, then going "get_class().case_comp(parent.get_class()), but it's kind of a hack. Being able to do things properly would be nice. :/
While you can use the class_name as type hints to parameters of methods of your class, you cannot use them for example in factory methods which will create new instances of the class. The latter will give you the error described by the OP. E.g.
extends Node
class_name Useful
func equals(p_other: Useful) -> bool:
return false
func copy() -> Useful:
return Useful.new()
will result in the describe error condition, and while equals
will work just fine, copy
will result in the parser complaining about a cyclic reference.
To resolve this issue, one must use get_script().new()
, e.g.
func copy() -> Useful:
return get_script().new(with-params)
and if you have a base class that implements this, you need to
func copy() -> TimeInfo:
return get_script().get_base_script().new(with-params)
This looks rather complicated, but it is a valid work around and also removes the need for the extraneous preload.
You can't use class_name type hints even in parameters if some other class also has a type-hinted reference to your class.
Having a main scene with
extends Node2D
func _ready():
var attribute : Attribute = null
And a separate class with:
extends Node
class_name Attribute
func function(other_attribute : Attribute) -> void:
pass
will still fail in eb98c5e04 with a cyclic dependency error, though removing either one of the Attribute hints will succeed.
Also in my particular project the cyclic dependency error is not shown by the editor so this manifests as a resource leak.
I hope my finding will help at least some of you.
Short: I could check own custom class when I used as operator.
Long:
I'm developing a mission objectives system for my game and use a hierarchy of nodes of custom class MissionObjectiveBase which have child nodes inheriting from this custom class.
I got the cyclic dependency error when I used the is
operator:
child is MissionObjectiveBase
but it worked fine when I used the as
operator:
child as MissionObjectiveBase
I use Godot 3.2.
@RomanKoziolek nice find! I've also tested and confirmed this to be working in 3.2!
It's just a pity that this kind of obscure hack is needed in the first place, so I hope this is properly fixed in GDScript soon...
This is a duplicate of #21461.
Most helpful comment
Temporary Workaround
I found a way to do what I want here, but it feels inelegant and renaming the script or moving it becomes a hassle.
but this still disallows me from using static typing since I can't then use
Self
as a valid type