-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Annotations in GDScript #20318
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 |
@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, Something like
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: 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 |
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.:
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.
If it were already good enough, we wouldn't receive feature requests for it.
The syntax is not finalized yet. It is quite probable that it won't replace |
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. 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...
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. |
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 If 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
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.
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:
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 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:
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 would rather have more keywords if people don't like a ton of keywords we can remove some of them
|
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...
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.
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:
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 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 Edit: note C# as attributes that allows you to combine them like so.. |
@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. |
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
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. |
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.
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.
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.
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 @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. EDIT:
unless it was able to be collapsed from the beginning of |
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).
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 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, 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_")
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 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 |
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 I think it's safe to say that most people use 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 After some time I've found a solution as described in #33620 (comment). As you may notice there, So, I guess it would be nice to remake Related proposal: godotengine/godot-proposals#260. |
Opened a proposal with more specific details: godotengine/godot-proposals#828 |
Superseded by the above proposal. |
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.export
too (Add a way to add categories to the script variables section from GDScript #4378, Add categories to GDScript exported variables #10303).onready
keyword with an annotation.setget
(it is kind of a weird syntax when you want only the getter).master
,slave
,sync
,remote
).tool
) or only in debug mode (related to Splitting editor and runtime scripts. #12837).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.
For passing arguments, it could work like functions:
Maybe without parentheses:
Or maybe use named parameters (and avoid the keyword):
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.The text was updated successfully, but these errors were encountered: