GDScript: Add `Self` to reference a class from inside
Add Self as a way to reference a class from inside its script.
class_name Global
const Constant := Self
class Extended extends Self:
pass
static func static_func(instance: Self) -> Self:
return instance
func instance_func() -> Self:
return self
func test():
assert(Self == Constant)
assert(Self == Global)
var extended := Extended.new()
assert(extended is Self)
var constructed := Self.new()
assert(constructed is Self)
var static_funced := Self.static_func(self)
assert(static_funced is Self)
var instance_funced := instance_func()
assert(instance_funced is Self)
var variable: Self = self
assert(variable is Self)
While at it converted extends in ClassNode from Vector<StringName> to Vector<IdentifierNode *> - for better error placement.
And in is_shadowing removed bool return type and added a check for shadowing built-in types (var Array := 3, such check was done only for members before).
Implements proposal #391.
This is a simple implementation and Self here always points to the class where it is used, but it does not change its meaning with inheritance:
class A:
static func create() -> Self:
return Self.new()
class B extends A:
pass
func _ready():
var x := B.create()
Here x will be A, not B. I think that maybe it is desirable for it to be B - to match context dependent behavior of (potential future) type self. In that case there is a need for a separate name for simple type presented here.
Here
xwill beA, notB. I think that maybe it is desirable for it to beB- to match context dependent behavior of (potential future) typeself. In that case there is a need for a separate name for simple type presented here.
Yes, if we decide to add late static binding (like in PHP), then it should be a separate keyword/identifier.
I'll close this one for now. I think that Self type can be expected to be a type of self, what @dalexeev mentioned as late static binding. I've moved fixes into separate PRs and now they are merged.
As for accessing class without global pollution, I think maybe some new annotation can solve it:
@global(false)
class_name Foo
And if it can support strings as a value for a global name it might allow to expose nested classes and maybe have uses in plugin development:
@global("LongPluginNameFoo")
class_name Foo
@global("GlobalBar")
class Bar: pass