Skip to content

Conversation

Macksaur
Copy link
Contributor

@Macksaur Macksaur commented Sep 22, 2025

This PR introduces a Self type, enabling developers to strongly type the self identifier. Which is particularly useful for fluent APIs, static helpers and object managers, where the type used to describe self, or an instance of such a type, would be repetitive, or constraining.

Motivation

Currently there is no native way to refer to the type of the current class (self). Users must resort to workarounds like:

  • Declaring a class_name, globally loading the class, and repeating the identifier a lot.
  • Using a pre-loaded meta-type (const Self := preload(<current filename>).

These approaches rely on the user to make right and understand the pitfalls. GDScript could help out. Since the current class is always known in context, a Self type provides a natural and ergonomic solution.

Example:

func do_this() -> Self:
  # Perform work
  return self

func do_that() -> Self:
  # Perform work
  return self

# elsewhere...
var x := my_object.do_this().do_that()

The type of the object is automatically preserved when used in a fluent interface, and maintains meaningful auto-complete! As a bonus, Self also survives refactorings without modifying the code as it is always current.

Implementation

The implementation is minimal, modifying only three areas in the GDScript analyzer and compiler to handle Self as a special case, similar to how Variant is already treated today. This ensures compatibility with existing codebases that may already use Self as a type or variable name. This path is a clean way to onboard the feature and expand upon down the line, if required.

Testing

Comprehensive tests have been added to validate Self in various scenarios and edge-cases. You may prune them to your liking, I wanted to ensure the correctness of the code, as its simplicity was surprising.

The primary use cases are best demonstrated in runtime/features/self_type.gd.

@Macksaur Macksaur requested review from a team as code owners September 22, 2025 00:42
@dalexeev
Copy link
Member

See also:

Last time, we stopped because of the issue of late static binding: should Self simply be an alias for the current class (in which the function, variable, etc. is defined) or should it also point to child classes in the case of method inheritance? PHP, for example, has two keywords for this purpose: self and static.

@Macksaur
Copy link
Contributor Author

Macksaur commented Sep 22, 2025

There is definitely value in having both. It would be a shame to start bikeshedding though. I am only interested in the non-runtime-form at present, and referring to the enclosing class.

Perhaps the future version of late static binding can be represented by another name? and this issue can be deferred? If not, it will be easy enough to rename this version's Self to something else. There's lots of possibilities.

@Ivorforce
Copy link
Member

Note that, if Self points to a child class, I think it would be possible to statically 'override' class functions:

class A:
	func a():
		print("A")

	func test():
		Self.a()

class B:
	func a():
		print("B")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GDScript: Add keyword to access the current class
3 participants