Skip to content

Commit ba34190

Browse files
authored
Merge pull request #11029 from dalexeev/gds-abstract-and-variadic-funcs
GDScript: Document abstract and variadic functions
2 parents 493212f + 7a7ac7d commit ba34190

File tree

3 files changed

+115
-20
lines changed

3 files changed

+115
-20
lines changed

_extensions/gdscript.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ def innerstring_rules(ttype):
324324
"is_instance_of",
325325
"len",
326326
"load",
327+
"ord",
327328
"preload",
328329
"print_debug",
329330
"print_stack",
@@ -396,6 +397,7 @@ def innerstring_rules(ttype):
396397
words(
397398
(
398399
# modules/gdscript/doc_classes/@GDScript.xml
400+
"@abstract",
399401
"@export",
400402
"@export_category",
401403
"@export_color_no_alpha",
@@ -404,6 +406,7 @@ def innerstring_rules(ttype):
404406
"@export_enum",
405407
"@export_exp_easing",
406408
"@export_file",
409+
"@export_file_path",
407410
"@export_flags",
408411
"@export_flags_2d_navigation",
409412
"@export_flags_2d_physics",

tutorials/scripting/gdscript/gdscript_basics.rst

Lines changed: 98 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,62 @@ Lambda functions cannot be declared static.
15721572

15731573
See also `Static variables`_ and `Static constructor`_.
15741574

1575+
Variadic functions
1576+
~~~~~~~~~~~~~~~~~~
1577+
1578+
A variadic function is a function that can take a variable number of arguments.
1579+
Since Godot 4.5, GDScript supports variadic functions. To declare a variadic function,
1580+
you need to use the *rest parameter*, which collects all the excess arguments into an array.
1581+
1582+
::
1583+
1584+
func my_func(a, b = 0, ...args):
1585+
prints(a, b, args)
1586+
1587+
func _ready():
1588+
my_func(1) # 1 0 []
1589+
my_func(1, 2) # 1 2 []
1590+
my_func(1, 2, 3) # 1 2 [3]
1591+
my_func(1, 2, 3, 4) # 1 2 [3, 4]
1592+
my_func(1, 2, 3, 4, 5) # 1 2 [3, 4, 5]
1593+
1594+
A function can have at most one rest parameter, which must be the last one in the parameter list.
1595+
The rest parameter cannot have a default value. Static and lambda functions can also be variadic.
1596+
1597+
Static typing works for variadic functions too. However, typed arrays are currently not supported
1598+
as a static type of the rest parameter:
1599+
1600+
::
1601+
1602+
# You cannot specify `...values: Array[int]`.
1603+
func sum(...values: Array) -> int:
1604+
var result := 0
1605+
for value in values:
1606+
assert(value is int)
1607+
result += value
1608+
return result
1609+
1610+
.. note::
1611+
1612+
Although you can declare functions as variadic using the rest parameter, unpacking parameters
1613+
when calling a function using *spread syntax* that exists in some languages ​​(JavaScript, PHP)
1614+
is currently not supported in GDScript. However, you can use ``callv()`` to call a function
1615+
with an array of arguments:
1616+
1617+
::
1618+
1619+
func log_data(...values):
1620+
# ...
1621+
1622+
func other_func(...args):
1623+
#log_data(...args) # This won't work.
1624+
log_data.callv(args) # This will work.
1625+
1626+
Abstract functions
1627+
~~~~~~~~~~~~~~~~~~
1628+
1629+
See `Abstract classes and methods`_.
1630+
15751631
Statements and control flow
15761632
---------------------------
15771633

@@ -2047,7 +2103,7 @@ If you want to use ``extends`` too, you can keep both on the same line:
20472103
Named classes are globally registered, which means they become available to use
20482104
in other scripts without the need to ``load`` or ``preload`` them:
20492105

2050-
.. code-block:: gdscript
2106+
::
20512107

20522108
var player
20532109

@@ -2070,30 +2126,45 @@ in other scripts without the need to ``load`` or ``preload`` them:
20702126

20712127
.. _doc_gdscript_basics_abstract_class:
20722128

2073-
Registering abstract classes
2129+
Abstract classes and methods
20742130
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20752131

2076-
Since Godot 4.5, you can register abstract classes using the ``abstract`` keyword.
2077-
An abstract class is a class that cannot be instantiated directly. Instead, it
2078-
is meant to be subclassed by other classes. Attempting to instantiate
2132+
Since Godot 4.5, you can define abstract classes and methods using
2133+
the ``@abstract`` annotation.
2134+
2135+
An abstract class is a class that cannot be instantiated directly.
2136+
Instead, it is meant to be inherited by other classes. Attempting to instantiate
20792137
an abstract class will result in an error.
20802138

2139+
An abstract method is a method that has no implementation. Therefore, a newline
2140+
or a semicolon is expected after the function header. This defines a contract that
2141+
inheriting classes must conform to, because the method signature must be compatible
2142+
when overriding.
2143+
2144+
Inheriting classes must either provide implementations for all abstract methods,
2145+
or the inheriting class must be marked as abstract. If a class has at least one
2146+
abstract method (either its own or an unimplemented inherited one),
2147+
then it must also be marked as abstract. However, the reverse is not true:
2148+
an abstract class is allowed to have no abstract methods.
2149+
2150+
.. tip::
2151+
2152+
If you want to declare a method as optional to be overridden, you should use
2153+
a non-abstract method and provide a default implementation.
2154+
20812155
For example, you could have an abstract class called ``Shape`` that defines
2082-
a method called ``draw()``. You can then create subclasses like ``Circle``
2156+
an abstract method called ``draw()``. You can then create subclasses like ``Circle``
20832157
and ``Square`` that implement the ``draw()`` method in their own way.
20842158
This allows you to define a common *interface* for all shapes without
20852159
having to implement all the details in the abstract class itself:
20862160

2087-
.. code-block:: gdscript
2161+
::
20882162

2089-
abstract class Shape:
2090-
func draw():
2091-
# It is possible for subclasses to call the parent class method using `super()`.
2092-
# In this example, we won't use `super()` to call the parent class method,
2093-
# so we can leave this method empty.
2094-
pass
2163+
@abstract class Shape:
2164+
@abstract func draw()
20952165

20962166
# This is a concrete (non-abstract) subclass of Shape.
2167+
# You **must** implement all abstract methods in concrete classes.
20972168
class Circle extends Shape:
20982169
func draw():
20992170
print("Drawing a circle.")
@@ -2102,16 +2173,17 @@ having to implement all the details in the abstract class itself:
21022173
func draw():
21032174
print("Drawing a square.")
21042175

2105-
Both subclasses and classes created using ``class_name`` can be abstract. This
2106-
example creates two abstract classes, one of which is a subclass of another
2176+
Both inner classes and classes created using ``class_name`` can be abstract.
2177+
This example creates two abstract classes, one of which is a subclass of another
21072178
abstract class:
21082179

2109-
.. code-block:: gdscript
2180+
::
21102181

2111-
abstract class_name AbstractClass
2182+
@abstract
2183+
class_name AbstractClass
21122184
extends Node
21132185

2114-
abstract class AbstractSubClass:
2186+
@abstract class AbstractSubClass:
21152187
func _ready():
21162188
pass
21172189

@@ -2132,6 +2204,14 @@ abstract class:
21322204

21332205
Cannot set object script. Script '<path to script>' should not be abstract.
21342206

2207+
Unnamed classes can also be defined as abstract, the ``@abstract`` annotation
2208+
must precede ``extends``:
2209+
2210+
::
2211+
2212+
@abstract
2213+
extends Node
2214+
21352215
Inheritance
21362216
~~~~~~~~~~~
21372217

tutorials/scripting/gdscript/gdscript_styleguide.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ Follow with the optional ``@icon`` then the ``class_name`` if necessary. You can
839839
GDScript file into a global type in your project using ``class_name``. For more
840840
information, see :ref:`doc_gdscript_basics_class_name`. If the class is meant
841841
to be an :ref:`abstract class <doc_gdscript_basics_abstract_class>`,
842-
add ``abstract`` *before* the ``class_name`` keyword, but on the same line.
842+
add ``@abstract`` *before* the ``class_name`` keyword.
843843

844844
Then, add the ``extends`` keyword if the class extends a built-in type.
845845

@@ -850,13 +850,25 @@ and how other developers should use it, for example.
850850

851851
::
852852

853-
abstract class_name MyNode
853+
@abstract
854+
class_name MyNode
854855
extends Node
855856
## A brief description of the class's role and functionality.
856857
##
857858
## The description of the script, what it can do,
858859
## and any further detail.
859860

861+
For inner classes, use single-line declarations:
862+
863+
::
864+
865+
## A brief description of the class's role and functionality.
866+
##
867+
## The description of the script, what it can do,
868+
## and any further detail.
869+
@abstract class MyNode extends Node:
870+
pass
871+
860872
Signals and properties
861873
~~~~~~~~~~~~~~~~~~~~~~
862874

0 commit comments

Comments
 (0)