godot
godot copied to clipboard
Add Trait System to GDScript
GDScript Trait System
Based on the discussion opened in:
- https://github.com/godotengine/godot-proposals/issues/6416
The GDScript trait system allows traits to be declared in separate .gdt
files or within a trait SomeTrait
block.
Traits facilitate efficient code reuse by enabling classes to share and implement common behaviors, reducing duplication and promoting maintainable design.
Syntax Breakdown
Declaring Traits
-
Traits can be defined globally or within classes.
-
In a
.gdt
file, declare a global trait usingtrait_name GlobalTrait
at the top.trait
used for inner traits. -
Traits can contain all class members: enums, signals, variables, constants, functions and inner classes.
Example:
# SomeTrait.gdt trait_name SomeTrait # Trait types used for typing containers. var player: TraitPlayable var scene_props: Array[TraitMoveable] var collected: Dictionary[String, TraitCollectable] func _ready(): pass # Method with implementation, but can be overridden. # Method to be implemented by the class using the trait. # The return type must be `void`. func foo() -> void # Bodyless need to be implemented in class using trait. # The return type can be overridden, but it's not required to specify one. func some_method() # Bodyless need to be implemented in class using trait. # The return type can be overridden but must be a class that inherits from `Node`. func some_other_method() -> Node # Bodyless need to be implemented in class using trait.
Using Traits in Classes
-
Use the
uses
keyword after theextends
block, followed by the path or global name of the trait. -
Traits can include other traits but do not need to implement their unimplemented functions. The implementation burden falls on the class using the trait.
Example:
# SomeClass.gd extends Node uses Shapes, Topology # Global traits uses "res://someOtherTrait.gdt" # File-based trait func _ready(): var my_animals : Array = [] my_animals.append(FluffyCow.new()) my_animals.append(FluffyBull.new()) my_animals.append(Bird.new()) var count = 1 for animal in my_animals: print("Animal ", count) if animal is Shearable: animal.shear() if animal is Milkable: animal.milk() count += 1 trait Shearable: func shear() -> void: print("Shearable ok") trait Milkable: func milk() -> void: print("Milkable ok") class FluffyCow: uses Shearable, Milkable class FluffyBull: uses Shearable class Bird: pass
Creating Trait files.
- In Editor go to FileSystem, left click and select "New Script ...". In the pop up select GDTrait as the preferred Language.
- Alternatively in script creation pop up instead of selecting GDTrait from 'Language' dropdown menu change 'path' extention to '.gdt' and GDTrait will automatic change to GDTrait
How Traits Are Handled
Cases
When a class uses a trait, its handled as follows:
1. Trait and Class Inheritance Compatibility:
The trait's inheritance must be a parent of the class's inheritance (compatible), but not the other way around, else an error occurs.
Example:
# TraitA.gdt
trait_name TraitA extends Node
# ClassA.gd
extends Control
uses TraitA # Allowed si nce Control inherits from Node
2. Used Traits Cohesion:
When a class uses various traits, some traits' members might shadow other traits members ,hence, an error should occur when on the trait relative on the order it is declared.
3. Enums, Constants, Variables, Signals, Functions and Inner Classes:
These are copied over, or an error occurs if they are shadowed.
4. Extending Named Enums:
Named enums can be redeclared in class and have new enum values.
5. Overriding Variables:
This is allowed if the type is compatible and the value is changed. Or only the type further specified. Export, Onready, Static state of trait variables are maintained. Setter and getter is maintained else overridden (setters parameters same and the ).
6. Overriding Signal:
This is allowed if parameter count are maintained and the parameter types is compatible by further specified from parent class type.
Example:
# TraitA.gdt
trait_name TraitA
signal someSignal(out: Node)
# ClassA.gd
uses TraitA
signal someSignal(out: Node2D) # Overridden signal
7. Overriding Functions:
Allowed if parameter count are maintained, return types and parameter types are compatible, but the function body can be changed. Static and rpc state of trait functions are maintained.
8. Unimplemented (Bodyless) Functions:
The class must provide an implementation. If a bodyless function remains unimplemented, an error occurs. Static and rpc state of trait functions are maintained.
9. Extending Inner Classes:
Inner classes defined in used trait can be redeclared in class and have new members provide not shadow members declared inner class declared in trait. Allow Member overrides for variables, Signals and function while extending Enum and its' Inner Classes.
Example:
# Shapes.gdt
trait_name Shapes
class triangle: # Declared
var edges:int = 3
var face:int = 1
func print_faces():
print(face)
# Draw.gd
uses Shapes
class triangle: # Redeclared
var verticies:int = 3 # Add a new member
var face:int = 2 # Overriding Variable
func print_faces(): # Overriding Function
print(face-1)
Special Trait Features
10. Trait can use other Traits:
A trait is allows to use another trait except it does not alter members of the trait it is using by overriding or extending.
11. Tool Trait:
if one trait containing the @tool
keyword is used it converts classes (except inner classes) and traits using it into tool scripts.
12. File-Level Documentation:
Member documentation is copied over from trait else overridden.
System Implementation Progress
- [x] Implement and verify How Traits Are Handled
- [ ] Debugger Integration
- [ ] Trait typed Assignable (variable, array, dictionary) - variable is done
- [ ] Trait type as method & signal parameters' type
- [x] Trait type as method return type
- [x] Trait type casting (
as
) - [x] Class is Trait type compatibility check (
is
) - [x] Make
.gdt
files unattachable to objects/nodes - [x] Hot reloadable Classes using traits when trait Changes (for Editor and script documentation)
- [ ] Write Tests
- [ ] Write Documentation