-
-
Notifications
You must be signed in to change notification settings - Fork 98
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
Export statements in GDScript are confusing #298
Comments
To add to this: there is not yet any way to have fine-tuned control over exports either, nor is there an idiomatic way of conveying what goes into defining an export because the entire concept of PropertyInfo and MethodInfo objects is hidden from the end-user. I would argue that being more direct with end-users about the use of *Info classes would go a long way towards clarifying and easing their use.
@KoBeWi The stated complaints about exports are applicable to all languages, not just GDScript, since each language currently takes a similar approach to defining exports, i.e. hides *Info objects from users. As such, I think this would be a concrete solution to making the experience of dealing with exports better for all languages. It also makes the documentation regarding reflection methods like |
@willnationsdev Can you elaborate what using such |
@pycbouh So, for example, a PropertyInfo struct represented as a Dictionary in GDScript (from, e.g.
When you declare that a property is exported, it automatically modifies the
The most direct way to control the content would be to have the ability to directly assign values to the PropertyInfo object. And in fact, C#'s
On the upside, it enables people to rely on the
Another example is exporting resources which must have And, unfortunately, absolutely none of this information is properly documented in the official documentation because it all happens behind-the-scenes in the engine code. And yet, there is just enough of it exposed to the end-user that they still need to know about it, and yet can't find any tutorials on it, any API docs about PropertyInfo/MethodInfo, any explanations as to how the property/method/signal serialization and reflection process works in the engine at all. You just have to be "in-the-know" by looking at the source code. So, aside from exposing all of this information, demanding that users use the full globals (to get autocompletion) and deal with full PropertyInfo structs (so that we can get them into the documentation), and then actually creating good documentation about the content and how it works, there isn't a lot more we can do. An example I could see of an updated version of GDScript using full stuff would be something like this (more verbose, but potentially has better autocompletion/docs):
I know @reduz at one point mentioned that he had ideas on how to improve/change the export process, but I'm not sure what those ideas entailed. Perhaps that could illuminate another path forward. If you really wanted to improve the readability of the codebase using PropertyInfos and whatnot, without taking options away from the user, I feel like you'd have to make deeper changes to the system and the way it works. |
What's funny is, if you look at the content that GDScript actually requires users to put in the export parameters, it really is just a more concise and readable version of the bare minimum of fields already present in the PropertyInfo struct. It lends itself to GDScript's readability. It just omits the
|
Good discussion so far. One way to maybe clarify things would be to add in context boundaries. This could be done with a list, which would also keep things backwards compatible (as export can just check for a list or not): # Export could take in arrays for sub-types.
export( Array, [int, "left", "center", "right"] ) var col_alignments
# This would allow export to have context-boundaries for its sub-types
export( Array, [Array, [int, "left", "center", "right"] ] ) var cell_alignments
# It would maybe also make it easier to support future types like
# dictionaries, where multiple sub-types will be needed
export( Dictionary, Array, int, int ) # confusing
export( Dictionary, [Array, int], int ) # less confusing
# even more complex example:
export( Dictionary,
[String, "StateA", "StateB", "StateC"],
[Array, [String, "StateA", "StateB", "StateC"] ]
) var transitions There are multiple variations of where the braces could go, so it may still be a bit confusing in the end. Overall, I would prefer a new syntax that was even more friendly, but I would settle for this fairly minimal change (syntax-wise. Don't know how hard it would be to implement code-wise.) |
Haven't read the full discussion, but we already have plans to change the |
@vnen are these plans detailed anywhere? I'm curious about it. |
@reduz did put some ideas in a document. I'll paste here the relevant for the Right now GDScript has it’s own export hint syntax, while Godot uses another one (check object.h). The one from Godot is very complete, but not much is available on GDScript. Added to this, given GDScript has optional typing, the old export syntax does not make much sense. I think we should Remove the old export syntax “export(type)” and just go with “export var something:type”. Examples for new syntax: The following are all the same: export(Enum,”One”,”Two”,”Three”) var myenum : int The following are also all the same: export(Range,0,100,1) var myrange : int Same here: export(File,”.png,.jpg”) file_path : String |
I like this idea, but what do you do to replicate features that have non-user-friendly manipulation of the hint string? For example, Array type hints have a very confusing hint string that stores multiple values in a specific format. In addition, I think we should enable users to supply custom usage flags this way, as the final parameter perhaps. |
@vnen
And the new one is:
In my opinion, if we are going to stick to some resemblance of the current syntax, because of the believe that it is easier to use for someone who is just introduced to the engine and its scripting language, then we should probably make the following adjustments:
That way we can keep a simple way to setup a simple case, but there will be a solution for those, that require finesse. |
First of all, draft isn't really mine. I was just sharing for context. We haven't discussed it yet, so don't treat it as final (hence why called "draft").
While I do agree that reading is important, the context of the hints is not a hindrance to understand what the code does. You know there's an export and the Those mentions of "syntax mess" for Arrays is more an issue of the current system than the new one. The new won't even need any hint, since we will have typed arrays anyway. Just use AFAIK there's no typed dictionaries. Not sure if it's gonna be added (by setting types for both key and value), but if so the explicit type specifier should be enough too.
It can still have code completion. The first argument to export is the hint, which is already a limited list. After selecting this, it can show the arguments types/format based on the hint. Having a different syntax for each hint would be much more taxing on memory than understanding the different strings (most are quite trivial to learn, only a few are quite hairy). They are treated as string (since they are used like this internally) but they need not to be. You can write with actual values (say, numbers for the range hint). I could concede having some restrictions based on the hint, so there's only a single way to do it, but that can get quite tricky to implement.
Well, I might have missed, but haven't seen a proposal here that solves the length issue. Only exception is annotations, since they go in their own line, but we likely won't use annotations for core features. In theory we could allow the
Which hints are introduced by this new system that were inferred before?
I don't think there'll be any nested structure. If anything, we're getting rid of those.
This makes sense only if the use case surfaces. Only thing I can see is changing the
Well, I can understand the critics to the syntax. But without a new counter-proposal to compare, it's hard to tell what you have in mind. I'm missing some new ideas in this thread. @willnationsdev gave a few examples in #298 (comment) but honestly they look harder to read than the current way. All-in-all, I did get some insights from the thread. I still think the new syntax will be simpler to write, read, and implement (even with completion support). The current |
Yes, that was clear. But given that it was still a proposition from a core team member on the same subject as my proposal, I gave it a quick evaluation from my perspective anyway. Did not mean to overly critique it as if it was final, sorry for misconception.
Aren't
In my latest comment, I've mentioned an export struct/typedef, that can be used as a sole argument for
At the very least, we could allow a multiline export statement, because as of 3.1.2 this is invalid:
How would you unpack this example from the docs, but with further hints for each inner type? For example, if that float is hinted as a range.
And though
I may not have an eye-opening example that shows how flawed export statements are currently. My main gripe is that what we as developers have right now is an attempt to crumple a complex system into a one-liner, which is by its nature very implicit. I see an appeal of such syntax for an ad-hoc solutions and it is easy to share with newcomers. But as a seasoned programmer I prefer to have explicit declarations in places, where there are multiple ways to configure script's logic. I don't see, how am I supposed to figure out from code that there is an option or how auto-completion can work in cases where we start to introduce new modifiers in between of old arguments:
What if there is a need for another flag like
Well, I suggested a way to replace a string of arbitrary hint arguments with a struct. So something like
can turn into
This is explicit, non-ambiguous and can be code-completed the same way that the list of properties is after a "dot". There is no need to introduce new statements, if multiline exports are allowed:
And with this addition, I would prefer to limit the scope of one-liner export statements to a subset of what is currently accepted, and introduce new options in export structs, rather than new hints. So, maybe we can have |
Yes, but you also need the type. Since the type won't be needed anymore, adding the hint won't increase the number of arguments. Also, for
That helps reading if you don't care about what the export does. Otherwise you'll have to scan for that type to understand it. But if don't care, you can just skip the hint entirely. Again, I feel like most of export hints will be quite short.
We will likely allow that anyway. Also, as I mentioned, we might allow the
Again, with typed arrays this won't be needed. Don't really have a syntax for that yet, but think something like this (borrowing from C++ templates/Java generics):
No hint needed at all, since it can be inferred from type.
AFAIK there's no editor support for typed dictionaries in the Inspector. No reason to consider as a language feature without editor support. Typing dictionaries is a bit more challenging if you are expecting a specific structure (I don't think this will ever happen). What might happen is setting one type for the keys and one for the values. Then again, no export hint would be needed since the variable can be typed.
Those modifiers will be removed. That's a main point of the simplification. Instead you'll do:
So there won't be "magical" arguments. There's only the property hint and the hint string with the specification when needed, the same way it happens internally. The point of the modification in the draft is exactly to get rid of those.
I don't think that's really super easier to read. As I mentioned above, if I want to know what the export does I need to scan the source to find it. If the export struct is right before the declaration than it makes the important part (as you said, the var declaration) further below. Note that the new system will get rid of the type and special arguments. In the end it'll be like this: export(GlobalFile, "*.png,*.jpg,*.bmp,*.gif") var tool_image Only two arguments: hint and hint string. It's not that long. If we allow a line break: export(GlobalFile, "*.png", "*.jpg", "*.bmp", "*.gif")
var tool_image
In this case, we have to understand a whole load of different structs, making the parser way more complicated. Honestly, how difficult is to understand when reading what kind of stuff this export needs: export(GlobalFile, "*.png,*.jpg,*.bmp,*.gif") var tool_image You know it's a global file, and should be easy to see that the string means the possible extensions. Now see the struct example: export({
extends: File,
is_global: true,
extensions: "*.png,*.jpg,*.bmp,*.gif"
}) var tool_image You have to scan way more text, cluttering the actual declaration. It's harder to tell if it's a global file, because you have to read the Think about how completion would work with a struct. The system will have to understand the struct (which will be in the middle of writing), it needs to see the Then for parsing this we would need to create a special struct for each kind of hint, and validate them all to make sure they are correctly filled. Then we need to create the PropertyInfo internally based on that struct. If a new PropertyInfo is created, we need to devise a new struct and update the GDScript parser before it's available for scripting. If besides that we allow a shorthand syntax from some cases, then we need to add still more effort to the parser to validate those. |
Honestly, I understand how the current syntax can be seem as magical and harder to understand the available options. But the draft I shared vastly simplifies that and remove all the magic that is. No more special arguments: only the hint and hint string. Instead of: export(float, EXP, 100, 1000, 20) var l You'll use: export(ExpRange, 100, 1000, 20) var l: float Instead of: export(Color, RGB) var col You'll use: export(ColorNoAlpha) var col If you don't need NoAlpha you can simply type the var: export var col: Color Same thing for other possible hints. |
@vnen Thanks for taking your time to reply in detail. I agree, that simplifications of the draft can make some existing cases easier to write and read. Plus, if multiline statements are supported, that can improve comfort even further. I just think in terms of extensibility, but I guess there is no need to overthink it for future proofing. Going to have to wait for that draft to be formalized and put to public discussion, then. |
BTW, I intend to use annotations for the export syntax, and I do believe it's much more clear, even than my suggestion here: #828 (comment) |
The export syntax has received an overhaul as part of the new GDScript, closing. |
Describe the project you are working on:
Not applicable.
Describe the problem or limitation you are having in your project:
Hinted export statements lack clarity, consist of arbitrary list of arguments and conflict with typed declarations. Single
export
keyword is clean and concise, but if hints are needed to support property editor, then having documentation handy is a requirement to deal with them, unless you have memorized it already.export
, and everything else is varying depending on the first argument (the hinted type), number of arguments, their types and special meaning, one cannot read and understand such statements without looking up the documentation, which is unfriendly to newcomers and a nuisance for advanced users.Describe how this feature / enhancement will help you overcome this problem or limitation:
Improving export statement syntax can make code clearer to read and and cleaner to write. This feature feels like it was introduced a long time ago and is heavily outdated in the current state of the language. I think, that in such state extended export hinting is unusable, unless you really need to have it.
Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:
Not applicable.
Describe implementation detail for your proposal (in code), if possible:
I can only imagine annotations as being a viable solution, which is suggested in #20318. However, this solution was not approved by the core team and is up in the air for the moment.
If this enhancement will not be used often, can it be worked around with a few lines of script?:
No.
Is there a reason why this should be core and not an add-on in the asset library?:
It involves GDScript parser and editor changes.
The text was updated successfully, but these errors were encountered: