Godot: Annotations in GDScript

Created on 21 Jul 2018  ·  45Comments  ·  Source: godotengine/godot

Around a year ago there was a PR adding annotations for GDScript (#9469). It was rejected mainly because there was no direct use for it (no data in the parse tree, only third-party tools would made use of it).

This proposal is to add some use for annotations in a way that make GDScript more extensible without hacking more keywords into it.

What annotations could be used for?

  • export hints. Right now it uses a custom syntax for each type. With annotations it could set directly the usage and hint for the PropertyInfo, making better use of new additions to the Inspector without having to hack a new syntax in the GDScript parser.
    To be clear, I would leave the export keyword, just the hints would move to annotations. Type can be defined with type hints.
  • This includes categories for export too (#4378, #10303).
  • Replace onready keyword with an annotation.
  • Disabling certain warnings. #19993 add warnings with an ad-hoc syntax for disabling them, but it could use annotations instead.
  • setget (it is kind of a weird syntax when you want only the getter).
  • RPC keywords (master, slave, sync, remote).
  • New pre-processor instructions, like making a function compile only in editor (with tool) or only in debug mode (related to #12837).
  • Eventual discussion of new syntax (like signal to emit when variable change: #6491).
  • Maybe the possibility of adding custom "decorators".

Advantages
Every time a new keyword is added, it requires changes to the GDScript tokenizer and parser to handle it. In particular the export parsing is quite convoluted and it's mixed with other class-related parsing.

With annotations, less work would be done to add a particular attribute (like export, setget, onready), instead it would only need to check which annotations are present.

DIsadvantages
Adding annotation support would require more changes to the parser than any keyword alone. It may also influence people to suggest new features as "just an annotation".

Syntax
I don't have any particular preference for syntax, but I imagine something like Python decorators. It might be confusing for Python users though, since annotations are not the same as decorators.

@onready
var my_sprite = $Sprite

For passing arguments, it could work like functions:

@export_hint(ENUM)
@export_hint_string("Attack,Defense")
export var my_enum : int = 0

Maybe without parentheses:

@export_hint ENUM
@export_hint_string "Attack,Defense"
export var my_enum : int = 0

Or maybe use named parameters (and avoid the keyword):

@export type=String hint=MULTILINE
var my_text = ""

Or something else.

Custom annotations
Unknown annotations will simply be ignored (maybe with a warning). So third-party tools can parse the annotations to offer other capabilities, like documentation generation.

It's also possible to add an introspection API: get_method_annotations(), get_property_annotations() or something like that. This way plugins that, say, expect scripts can use annotations to decide which method to call instead of using a hard-coded name.

archived discussion feature proposal gdscript

Most helpful comment

why is gdscript's syntax being modified so heavily? it was originally designed to be simple, easy to learn and intuitive. i fear with all these new additions (typed gds, annotations) it will become very confusing for new developers.

Most (if not all) GDScript syntax changes are compatible with old code. The main goal is to increase productivity of developers using GDScript, e.g.:

  • match statements allow for switch-case statements (which were quite requested) and even improve upon that by allowing people to match arrays and dictionaries with ease.
  • onready variables (which were new in 2.x) concretize a pattern which was often used, namely initializing variables in _ready.
  • Typed GDScript allows developers to finally rest knowing that no wrong-type errors will happen, and lets them benefit from better autocomplete at the same time. It is optional, so newcomers don't need to learn it for their first game.

i just feel like there might be a possible disconnect between actual game devs, and the contributors.

This is an open community. Game devs are welcome to come and express their opinion, just as you did. At any rate, quite a bit of time will pass before annotations become a reality.

[...] i just fear that gds might stray further and further away from its simplicity, that's all. it's already more than enough...

If it were already good enough, we wouldn't receive feature requests for it.

also, having 3 lines for a export keyword is very cumbersome, compared to just specifying everything in one line. for example: onready var my_sprite = $Sprite is so much more cleaner

The syntax is not finalized yet. It is quite probable that it won't replace onready and export keywords immediately.

All 45 comments

Just so I'm understanding the custom annotations correctly, I could have something like this:

@description "Adds two numbers and returns the result."
@parameter name=num1 type=float description="The first number"
@parameter name=num2 type=float description="The second number"
@returns type=float description="num1 and num2 added together"
func add(num1, num2):
    return num1 + num2

And I could call a function, say get_annotations("add"), which would return these annotations? Even if these annotations aren't recognized by Godot as some built-in keyword/annotation?

@LikeLakers2 yes, that is the gist of it.

I like it, I dont know for the implementation behind but in the GDscript code it would look a lot cleaner than what it looks like now. Especially for the setget example.

This is very useful, but it should allow single line statements for readability. For example,
@onready var a = $A should be allowed. Otherwise, this adds a ton of newlines and would in this case waste the useful of onready.

Something like

@onready
    var a = $A
    var b = $B
    var c = $C

would be useful to apply the same annotation to several statements.

Also, a colon could be used to indicate where the annotation ends and where the affected statement(s) begin, to be consistent with the rest of GDScript.

If annotations can be parsed with a clear begin and end, then no need for semicolons and can then be put on the same line if needed (if they use '()' for example, or are argument-less)

I don't think vnen intended to remove old shortcut keywords though?

Also having highlighter handle these can help.

Late to the party here, but very interested in how this might provide categories for export vars and create tool/debug script divisions?

Tentatively putting on the 3.2 roadmap, I'd really like to see this implemented sooner than later to provide usability enhancements to the editor.

#### unpopular opinion incoming:

why is gdscript's syntax being modified so heavily? it was originally designed to be simple, easy to learn and intuitive. i fear with all these new additions (typed gds, annotations) it will become very confusing for new developers. for example, if a new person to godot were to watch a tutorial and see the code that's in LikeLakers2's post, i'd imagine that would make their head explode. if anything they'd have to ask bunch of questions about it / how it works, etc.

i totally understand everyone's love for gds and how the contributors want to make it better, etc. i just feel like there might be a possible disconnect between actual game devs, and the contributors (not saying contributors are not game devs, just saying how some features are not really needed). not everyone needs to utilize these features. i just fear that gds might stray further and further away from its simplicity, that's all. it's already more than enough...

also, having 3 lines for a export keyword is very cumbersome, compared to just specifying everything in one line. for example: onready var my_sprite = $Sprite is so much more cleaner (to me anyway)

and regards to point #4, this can be done in the editor AFAIK. also, imo, having annotations all over the place in code to 'disable certain warnings' could lead to very messy code

why is gdscript's syntax being modified so heavily? it was originally designed to be simple, easy to learn and intuitive. i fear with all these new additions (typed gds, annotations) it will become very confusing for new developers.

Most (if not all) GDScript syntax changes are compatible with old code. The main goal is to increase productivity of developers using GDScript, e.g.:

  • match statements allow for switch-case statements (which were quite requested) and even improve upon that by allowing people to match arrays and dictionaries with ease.
  • onready variables (which were new in 2.x) concretize a pattern which was often used, namely initializing variables in _ready.
  • Typed GDScript allows developers to finally rest knowing that no wrong-type errors will happen, and lets them benefit from better autocomplete at the same time. It is optional, so newcomers don't need to learn it for their first game.

i just feel like there might be a possible disconnect between actual game devs, and the contributors.

This is an open community. Game devs are welcome to come and express their opinion, just as you did. At any rate, quite a bit of time will pass before annotations become a reality.

[...] i just fear that gds might stray further and further away from its simplicity, that's all. it's already more than enough...

If it were already good enough, we wouldn't receive feature requests for it.

also, having 3 lines for a export keyword is very cumbersome, compared to just specifying everything in one line. for example: onready var my_sprite = $Sprite is so much more cleaner

The syntax is not finalized yet. It is quite probable that it won't replace onready and export keywords immediately.

I really like the idea, very like attributes in C#.

Classes and signals annotations could be interesting as well.

Inspector plugins that automatically come in action whether a property, method or class have a particular custom annotation would be a breeze.
As for the syntax I'd prefer something that could be optionally written on a single line too, but it's not so crucial.

How the process of defining custom annotations could be? I would prefer that they were not freely defined every time in the code, but that they were created by the user with a univocal definition, just like classes.

I think this needs more looking into, I think it'd be great to add to the language (as optional syntax etc etc) so as to not confuse complete newbies trying to jump in.

I think the following syntax might be ok to look at:

@export type=String, hint=MULTILINE

adding the comma between the "parameters" I think would make it a little more consistent with the current syntax like so:

export (String, MULTILINE) var my_var

the first version is a little more verbose, but I think it also makes it more explicit and with autocomplete it shouldn't hurt too much :)

More syntax discussions should happen going forward. Overall I like the idea.

Annotations are a good way of configuration injection. But seperating configuration and code may be a more clean approach IMO. May be adding them like as header files be more helpfull.

From @bojidar-bg's comment...

At any rate, quite a bit of time will pass before annotations become a reality.

Can someone explain what the "blocking" issue is that would delay this implementation? Is it just familiarity with GDScript / manpower, or are there specific features that need to be implemented ahead of time to support annotations?

Well, quite a bit of time has passed since my comment, so I think that already proves it?

Main blocker for annotation support would be getting core developers agree on the syntax and semantics. Afterwards, implementation should be relatively easy.

We need to discuss this with @reduz since he prefers that annotations are only meant for metadata, they shouldn't affect script or editor behavior. This would make my original proposal quite pointless.

I still think annotations are clear enough, especially when replacing single keywords (onready, master, puppet, etc.). But we still need to reach a consensus.

I think this would be a fantastic addition to GDScript as described. I don't think it should be limited to metadata, it should definitely overtake many of the keywords that are used for variables, especially export which can get a little hard to read in some cases; splitting it up into multiple statements helps with comprehension, I feel.

It can also be used to solve that 3 year old issue #6204 in an elegant fashion:

@export
@export_tooltip "The name used when displaying this item in the inventory and in shops."
var display_name := ""

I also agree that they should support more than just metadata. It would simplify a lot of logic and improve readability imo.

I agree with @willnationsdev and I would love to connect signals by code using annotations, something like this can really improve the code readability:

@connect("timeout")
func _on_Timer_timeout():
   ...

@rluders assuming that script is on a Timer node, maybe.

@Zylann of course. Just a simple example. It could support the "target" parameters and omit it for self-connecting. For example, if the script is running outside the Timer:

@connect("timeout", $Timer)
func _on_Timer_timeout():
  ...

I have no idea how this could be implemented, but would really love to see annotations in gds, especially for keywords. And for the record, I would prefer it if '()' is used instead of semicolons or newlines to separate annotations.

It would be even better if we could create our own annotations + full blown annotation processors.

@Zylann of course. Just a simple example. It could support the "target" parameters and omit it for self-connecting. For example, if the script is running outside the Timer:

@connect("timeout", $Timer)
func _on_Timer_timeout():
  ...

That could be supported by a plugin in some way, I wouldn't make it a core feature.
Plugins could get even more powerful.

all i can say is that i'm glad i learned gdscript before these things got implemented because

@export_hint(ENUM)
@export_hint_string("Attack,Defense")
export var my_enum : int = 0

would have been very daunting and difficult to parse for me, as a beginner

@sleepcircle We will try to keep GDScript simple in all cases. So, no need to be sarcastic here: the code you cited was just a proposal, not _the_ future syntax.

I'm sorry, I wasn't trying to be sarcastic. I was just assuming, since the majority seemed to approve of these additions, that they were inevitable.

Just wanted to throw my $0.02 as a game dev instructor. Warning: Unnecessarily long comment that doesn't contribute much, just my experience from teaching programming for 5 years about how new developers will perceive this. Skip if not interested!

I think it's important when coming up with new language idioms like annotations that you should piggyback every affordance you can. For example with connect, it works nicely now as it makes sense to a new developer that you call a function that takes in parameters and has some side-effects.

If @ was used for metadata exclusively, then any time a new developer sees an @ they recognize it as metadata that doesn't affect their code logic. If it were to affect logic, it is important that we aren't adding new idioms that are sometimes used as x and sometimes used as y.

Right now, to modify a variable, there are var prefixes, suffixes, and alternatives. There are some things I'll list that aren't necessarily "variable modifiers", but new developers might see them this way

  • Prefixes: onready, export(...)

    • These each have a different type of behaviour. onready affects runtime variable loading, export is kind of an editor hint/metadata. Having them used in the same place feels like their behaviour should be connected somehow, when it really isn't

  • Alternatives: class_name, extends, signal, enum, const, func

    • These alternative formats feel fine, but differentiating an "enum" and "const" from say, ints or strings seems like an odd choice

  • Suffixes: setget

    • Setget in its own category is all right, but it is similar to export in that it is more a sugar keyword for developers and not-so-much a logic shift. I can see people having different opinions here, though

  • Somewhere in-between: typing var x : int = 5

    • This in-between typing feels odd, especially when "enum" and "const" are alternative keywords to var to represent the same thing. Definitely an argument that const is similar to setget in that it modifies the developer's experience moreso than a tool for game logic itself.

So now let's look at the addition of annotations.

Annotations would be a brand-new concept/idiom that would need to be taught to new developers. Ideally, new developers should be able to get up to speed and making things knowing as few idioms as possible so that they can organically pick up new idioms as they become useful to them. Think of it like a tech-tree.

  • (Tier 1) They can make a game knowing only func, var, and a few basic programming concepts like function calls, conditionals, and loops
  • (Tier 2) Then they move on to learn useful sugar/functionality, like signals, const, enum
  • (Tier 3) They learn shortcuts, like setget, onready
  • (Tier 3.1) They learn developer-only sugar, that won't change their game, but change their process, with things like exports, editor descriptions, tools, and typing
  • (Tier 4) Purely documentation and project structure

I feel like Tier 3-4 are the prime targets for annotations. There are two elevator pitches I'd give to my students for the two different implementations:

  • Purely metadata: "To help with your documentation and collaboration, learn about annotations to add some metadata to your scripts. They're more powerful than just using comments."
  • Dev shorthands/sugar: "If you're looking to reduce your code or make it more readable, have a look at annotations. They let you describe variables and functions while providing some editor tools and shortcuts."

I've taught a number of devs Godot, and I think making annotations at least a Tier 3 option, and at most Tier 4. I'd rather not have to show them an @ symbol until they're already building entire, reasonably complex games and are looking to improve their process.

This means my opinion lands on us using annotations exclusively for dev shorthands that are not important for game functionality/have alternative implementations or purely for documentation, as it's easy to tell people "learn annotations once you're building larger projects that need documentation".

Specific points from the thread:

  • They should be all right for exports, since exports aren't critical to any game
  • Onready is a handy shortcut early on, but not necessary since new devs can start by initiating in _ready and the prospect of nested annotations means writing onready way fewer times
  • setget is such a weird syntax already, and already its own idiom as the only suffix, that it could totally be in there
  • Connect: As I lead with, it's already perfect with the function call idiom. Having multiple ways to connect could conflate the tutorial/sample code space. Perhaps allowing people to write their own annotations would be better than standardizing this, so that devs working on closed projects can build a library of annotations that won't necessarily conflate the public space
  • Types: Types are in a weird spot right now, where some type modifiers are alternatives and some type modifiers are in-between. Maybe having them as annotations works: @type(const int) @type(enum), which would unify all of them as a developer-oriented sugar

Again, not a huge contribution, but food-for-thought when thinking about what functionality should be blanketed under annotations. I think they're a great idea, but unclear precisely where they fit in. Sorry for the length, I'm always a little too verbose.

I dislike this.
I don't want to have a bunch of annotations for every field, property and method

I would rather have more keywords

if people don't like a ton of keywords we can remove some of them

export MyClass : Node2D # export replaces class_name, : replaces extends 

signal mySignal #signal is kept

group(MyHeader, "res://icon.png" )
export var my_property : Array(int) setget _set_my_property, _get_my_property # : replaces export type

var test = 0 # no need for onready. variables declared outside of _ready automatically try to be onready vars

#others are kept

I agree with the original proposal entirely.

I don't disagree with the above comments, but the pros severely outweigh the cons.

@Shadowblitz16 Many of these suggestions are confusing to people here, for the following reasons...

export MyClass : Node2D # export replaces class_name, : replaces extends

export, class_name, :, and extends each configure 4 completely separate data points and systems. You cannot simply switch them around without impacting other things irrecoverably.

  • export configures the generated PropertyInfo object that is sent to the Inspector to build the editor GUI.
  • class_name registers the script as a global class in the ScriptServer. It technically has nothing to do with the type system. It's part of GDScript's "static typing" only insofar as it just happens to create a global instance of the script at parse-time rather than run-time.
  • : is used for optional type hints. Unless you convince people to make GDScript statically typed at all times and/or propose an alternative type hint syntax, there's no way to repurpose the colon token.
  • extends is used for the inherited class (as you know). This is a pretty common syntax in other languages, and all documentation and tutorials already follow this method. There isn't going to be a strong incentive to switch away from this and create more work for purely a cosmetic reason.
group(MyHeader, "res://icon.png")

It's unclear to me what this would even do. I mean, it seems like the node will be added to the "MyHeader" group (which could make sense), but what is the icon for? Groups do not have icons associated with them.

export var my_property : Array(int) setget _set_my_property, _get_my_property # : replaces export type

As has been stated earlier, these things all affect different systems, not the same system. Furthermore, there may be times that you want a value's type or its initialization to be flexible. For example, in dynamic GDScript, you can do something like this:

onready export(NodePath) var the_node = get_node(the_node)
var test = 0 # no need for onready. variables declared outside of _ready automatically try to be onready vars

Initializing data prior to the ready notification wouldn't make sense. Scripts are associated with the Object class, not the Node class. Script properties are initialized during construction. That doesn't change even when you get to the Node class's constructor. The _ready() notification happens much later after instantiation. Having the default timing of variable initialization be different between Objects and Nodes would be extremely confusing and lead to a lot of unpredictable behavior for those learning and using Godot.


I don't mean to shoot down your suggestions, but rather just explain why people are not seeing the justification for these suggested changes.

@willnationsdev its ok I understand
what about doing both Annotations and extra Keywords
this way users can use Annotations if they like and Keywords if they don't want to have dozens of Annotations per field

Edit: note C# as attributes that allows you to combine them like so..
[Attribute1(), Attribute2()]
however while this might help reduce the line count its still is a bit ugly

@Shadowblitz16 We'd prefer to have only one obvious way to do things when possible. Having two different syntaxes would be contrary to that goal.

@Calinou I think gdscript should be left as it is then if people can't compromise.
1 - it breaks backwards compatibility unnecessarily
2 - it creates bigger files and less readable code
3 - it forces people change to a new system they are not used to.
4 - it forces people to use a system that they might not want to

1 - it breaks backwards compatibility unnecessarily
2 - it creates bigger files and less readable code
3 - it forces people change to a new system they are not used to.
4 - it forces people to use a system that they might not want to

Honestly, those are quite bad arguments. 3 out those 4 points is inherent to any big changes in an API, and the first out of them could be worked around by still keeping compatibility with the older keyword-based system for a while (likely with a deprecation warning).

_Edit: we could also provide an automatic conversion tool I guess._

For point 2, while I think everyone will agree on the fact annotations can lead to files with more lines, most people here disagree on the fact it creates less readable code.

@groud this is using an annotations for unnecessary things
1 - why do we need to deprecation something that works?
2 - its less readable if you have to scroll down 5 lines to see a field

  • export is basically a public keyword to the editor
  • onready is basically a var declaration before the script runs

both are not suited to be annotations

member definitions are the only thing I can really see this being good for and they would have to be collapsible in this case they aren't.

@groud this is using an annotations for unnecessary things

A lot of use cases have been presented in this thread. Whether it is for documentation, introspection, more complex plugins... there a ton of use cases for annotations that cannot be covered by keywords.

1 - why do we need to deprecation something that works?

There are plenty of reasons to do something like that. Any feature might need to evolve to allow a cleaner API, more flexibility, etc... And once a new version is widely used, it's better to remove compatibility with previous version when possible, as this definitely has a maintenance cost.

2 - its less readable if you have to scroll down 5 lines to see a field

No need to exaggerate. The goal of discussing such proposal is to allow a syntax smart enough to avoid such problems. IMHO, the export hints could be integrated as arguments to the export annotations (provided we could have a named arguments system I guess). In such situations, the system could take even less space than before.

Also, we could also imagine having the annotations on the same lines as the field. I don't think this could cause problems.

export is basically a public keyword to the editor
onready is basically a var declaration before the script runs
both are not suited to be annotations

Well, you likely have preconceived ideas about what annotations are for. I do think those use case perfectly fit an annotation system (and it looks like a lot of people do). But indeed, I guess each situations should be discussed case by case.

I don't see the "lines" argument to be particularly good. Even if the annotations don't directly allow multiple statements per line (or a "prefix" form), you can still use ; as a delimiter.

@onready var my_sprite = $Sprite
@onready; var my_sprite = $Sprite


@export_hint_string("Attack,Defense")
@export_hint(ENUM) export var my_enum : int = 0

@export_hint_string("Attack,Defense")
@export_hint(ENUM); export var my_enum : int = 0


@export_hint_string "Attack,Defense";
@export_hint ENUM export var my_enum : int = 0

@export_hint_string "Attack,Defense"
@export_hint ENUM; export var my_enum : int = 0


@export type=String hint=MULTILINE; var my_text = ""

# more options

@export(type = String, hint = MULTILINE) var my_text = ""
@export(type = String, hint = MULTILINE); var my_text = ""

@export(String, hint = MULTILINE) var my_text = ""

# I personally prefer this one (positional and named args supported, default/optional args too)
@export(String, MULTILINE) var my_text = ""
@export(String, hint = MULTILINE) var my_text = ""
@export(type = String, hint = MULTILINE) var my_text = ""
@export(int, ENUM, "Attack,Defense") var my_enum:= 0

Edit: Oh, I was too slow, @groud already addressed the lines argument. Well, at least those few code examples added something to this thread.

that's your guys opinion.
I personally think the @ is ugly

EDIT:
so how would member declaration work?
doing so would be horriable

@description "Adds two numbers and returns the result."
@parameter name=num1 type=float description="The first number"
@parameter name=num2 type=float description="The second number"
@returns type=float description="num1 and num2 added together"
func add(num1, num2):
    return num1 + num2

unless it was able to be collapsed from the beginning of @description to the beginning of func

I believe annotations are not meant to replace types (as your example seems to do). If you don't want documentation annotations, you won't be forced to use them:

func add(num1: float, num2: float) -> float: return num1 + num2

This confusion probably stems from the less than ideal situation with export hints where, as far as I know, you can't use real types (and the problem of not having generic types which surprisingly export hints support for some types like an array).

I personally think the @ is ugly
so how would member declaration work?
doing so would be horriable

In other languages this purpose usually serve comments, not annotations and usually are on par or more verbose than what was suggested. In a C language family (most popular languages) the @ is pretty common for annotations (e.g. Java, JavaScript, TypeScript, Scala and from what I read Python as well).

TypeScript (I believe the types in docs are not required and tools can use actual types):

/** Adds two numbers and returns the result.
 * @param num1 {float} The first number
 * @param num2 {float} The second number
 * @return {float} num1 and num2 added together
  **/
const add = (num1: number, num2: number): number => num1 + num2;

func-like flavor:

@description("Adds two numbers and returns the result.")
@parameter(num1, "The first number", type=float)
@parameter(num2, "The second number", type=float)
@returns("num1 and num2 added together", type=float)
func add(num1: float, num2: float) -> float:
    return num1 + num2

without duplicate types:

@description("Adds two numbers and returns the result.")
@parameter(num1, "The first number")
@parameter(num2, "The second number")
@returns("num1 and num2 added together")
func add(num1: float, num2: float) -> float:
    return num1 + num2

paren-less flavor:

@description "Adds two numbers and returns the result."
@parameter num1 "The first number"
@parameter num2 "The second number"
@returns "num1 and num2 added together"
func add(num1: float, num2: float) -> float:
    return num1 + num2

I like this syntax best for doc comments. I am still not convinced about using annotations for documentation purposes, since for non-doc annotations I would prefer func-like syntax.

I used annotation names from the previous example, @parameter could be simply @param as in other languages, @description could be @desc, @descr or @func.

In GodoDoc I am using syntax based on TypeScript (TypeDoc which itself is based on JSDoc and Javadoc) and, in my opinion, it seems to work quite well:

## Same as [[bool_]], but `on_false`/`on_true` are functions.
## Only selected function will be called and its return value will be returned from `bool_lazy`.
## @typeparam T {any} Return type
## @param cond {bool} Condition
## @param on_false {FuncLike<T>} Function to call and return its result when `cond` is `false`
## @param on_true {FuncLike<T>} Function to call and return its result when `cond` is `true`
## @return {T}
func bool_lazy_(cond: bool, on_false, on_true): return GGI.bool_lazy_(cond, on_false, on_true)
var bool_lazy = funcref(self, "bool_lazy_")

unless it was able to be collapsed from the beginning of @description to the beginning of func

Yes, generally folding and an options for default folding would be a nice addition to the editor (folding based on a type of a block, e.g. you could enable in settings that inner classes would be collapsed by default).

I like the ability to put an annotation in front or above, for this the @annotation(a, b) is nice, with brackets optional if no params given. Being able to put in front allows the same speed of writing as today's keyword, given export and onready are very common with properties.

However in terms of usage, I dislike documentation too. I'm used to annotations having an effect on the program (even if indirect), while documentation would often triplicate their amount for comment-like usage, would then appear everywhere and highlighted the same as functional annotations... it's not fit for something that ubiquitous. Basically, I like the same usage of annotations as can be found in C#, which leads to far less annotations having to be written on top of members (they are pretty rare usually, not everyone has to write 5 lines as some examples have shown). If the argument is about Godot having no API to specify script docs, then that's the problem, not to be solved solely with annotations IMO. At least, I guess one could use that optionally, but I wouldn't want to be forced to do it this way, which I find inconvenient for full-scale documentation. (besides, scripts are not only GDScript, and edge case of using _get_property_list makes this even more awkward)

I think I fully agree with you Zylann. I would personnally allow such syntax for export (or onready) like keywords:

# No parenthesis when there are no parameters
@export var myvar
# With parenthesis for parameters
@export(ENUM, "Up,Down,Left,Right") var myvar2
# Being able to write the annoation on the line before
@export(ENUM, "Up,Down,Left,Right") 
var myvar2

Regarding the documentation part, I would simplify the syntax even more (taking @mnn 's example):

@description "Adds two numbers and returns the result."
@parameter "The first number" # No need to name the args if they are ordered
@parameter "The second number"
@returns "num1 and num2 added together"
func add(num1: float, num2: float) -> float:
    return num1 + num2

However, I agree it is mandatory to develop another system so that the documentation can be written elsewhere. In a json, XML or rst file I'd say. In-code documentation does not fit every project, and I agree adding a lot of annotation just for documentation might be annoying and can make the code harder to read in some cases.

Linking for relevance: godotengine/godot-proposals#177

Pretty late to the party, but as dev who heavily relies on metadata and reflection to develop plugins I would really love to see annotations become a thing in godot.

While I do think it makes some stuff more beatiful (like the export and onready stuff) my main argument would be for custom plugins that can utilize annotations to their fullest extend.

Regarding onready keyword and its limitations.

I think it's safe to say that most people use onready to initialize node references early on. Except that it might not be feasible without issues in the long run, because when you instance some scenes which are _ready dependent, you may stumble upon an issue of referencing null:

func explode():
    var bomb = preload("res://explosion.tscn").instance()
    # Oops, forgot to `add_child(bomb)` earlier
    bomb.fuse.wait_time = 5.0 # ERROR: fuse is `null`
    add_child(bomb)
    # ... because `fuse` is a $Timer node 
    # which is only initialized once added to the scene tree.

Of course you need to add_child() the instanced scene before trying to set the fuse, but what if other nodes/objects need to be aware of the exact fuse before the scene is added to the scene tree?

After some time I've found a solution as described in https://github.com/godotengine/godot/issues/33620#issuecomment-559999681. As you may notice there, onready is just NOTIFICATION_READY, while what I actually needed was NOTIFICATION_INSTANCED and initialize my references even earlier. The only problem is that there's no oninstanced keyword, and I guess you may figure out what I'm leading to. 🙂

So, I guess it would be nice to remake onready keyword as an annotation indeed, while also supporting some other corner cases (like mine, as always!) with @oninstanced functionality without bloating the scripting language, as well as adding support for other notifications pertaining to initialization (_init, _enter_tree, etc).

Related proposal: godotengine/godot-proposals#260.

Opened a proposal with more specific details: https://github.com/godotengine/godot-proposals/issues/828

Superseded by the above proposal.

Was this page helpful?
0 / 5 - 0 ratings